{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b8d19af0",
   "metadata": {},
   "source": [
    "# Robust Transformer-Based Approach for Intrusion Detection System"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8ebcc0a",
   "metadata": {},
   "source": [
    "Implementation by Malte Andersch, Student-ID 5571996"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30f1c650",
   "metadata": {},
   "source": [
    "In this Notebook, I will explore and experiment with the Proposed [RTIDS](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9794665) Architecture by Wu et Al. I will first describe the individual Components before evaluating the Performance of the Model and analyzing the Results. Finally I will compare the Perfformance of the RTIDS Archtiecture with an Encoder-Only Approach to the Same Problem.\n",
    "\n",
    "For running any of the code samples, please install the requirements listed below. You will also need to install PyTorch, but since the exact command depends on your system and conda/pip, I will not list any command for it here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41951bfc",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "!pip install einops\n",
    "!pip install numpy\n",
    "!pip install pandas\n",
    "!pip install scikit-learn\n",
    "!pip install imbalanced-learn"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69c72759",
   "metadata": {},
   "source": [
    "## Architecture"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3a42639",
   "metadata": {},
   "source": [
    "### Embedding\n",
    "In Network Intrusion Detection Systems, we mostly work with Numerical Values and not specific Tokens, thus we cannot apply traditional Token Embedding Techniques. However, since the authors of RTIDS did not specify their chosen Approach, I opted for the \"Feature Tokenizer\" Approach, described by Gorishniy et Al. in [Revisiting Deep Learning Models for Tabular Data](https://arxiv.org/pdf/2106.11959v2.pdf), thus normalizing all numerical Values in the Range 0. - 1. and then applying a linear Transformation to obtain a vector of the model dimension for each Attribute. While the Normalization happens in Data Preprocessing, the Linear Transformation is (since it is a Trainable Parameter) applied in the Embedder Module."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a2db1fe6",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "import torch \n",
    "from einops import rearrange\n",
    "\n",
    "class RTIDS_Embedder(nn.Module):\n",
    "    def __init__(self, dim, num_numerical_types=78):\n",
    "        super().__init__()\n",
    "        self.weights = nn.Parameter(torch.randn(num_numerical_types, dim))\n",
    "        self.biases = nn.Parameter(torch.randn(num_numerical_types, dim))\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = rearrange(x, 'b n -> b n 1')\n",
    "        return x * self.weights + self.biases"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81950ce4",
   "metadata": {},
   "source": [
    "### Positional Encoding\n",
    "Since the linear Operations of a Transformer Model would ignore any sort of positional Relation between Features, we apply Positional Encoding to the Input. Here we use Standard trigonometric Functions to add positional Information to each Attribute. The following calculation is performed:\n",
    "$$PE(pos, 2i) = \\sin(pos/1000^{2i/d\\_model})$$\n",
    "$$PE(pos, 2i+1) = \\cos(pos/1000^{2i/d\\_model})$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e4dea8c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.autograd import Variable\n",
    "from math import cos, sin, sqrt\n",
    "\n",
    "class RTIDS_Positional_Encoder(nn.Module):\n",
    "    def __init__(self, d_model, max_seq_len = 78):\n",
    "        super().__init__()\n",
    "        self.d_model = d_model\n",
    "\n",
    "        pe = torch.zeros(max_seq_len, d_model)\n",
    "        for pos in range(max_seq_len):\n",
    "            for i in range(0,d_model,2):\n",
    "                pe[pos,i] = sin(pos / (1000**(i/d_model)))\n",
    "                pe[pos,i+1] = cos(pos / (1000**(i/d_model)))\n",
    "        \n",
    "        pe = pe.unsqueeze(0)\n",
    "        self.register_buffer(\"pe\",pe)\n",
    "    \n",
    "    def forward(self, x):\n",
    "        x = x * sqrt(self.d_model)\n",
    "        seq_len = x.size(1)\n",
    "        y = Variable(self.pe[:,:seq_len],requires_grad=False).cuda()\n",
    "        x = x + y\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7106c20c",
   "metadata": {},
   "source": [
    "### Attention\n",
    "The Multi-Head Attention Mechanism is the Core part of any Transformer Model. Despite unclear definitions in the original RTIDS Paper regarding their use of the Multi-Headed Approach (Images displaying each Head as analyzing a different Sequence instead of the same Sequence with different sections of the Weight Matrix) I used the well-known implementation for the attention mechanism.\n",
    "The Attention Module decribed below is used for Multi-Headed Attention as well as for Masked Multi-Head Attention.\n",
    "The general calculation is seen in this formula:\n",
    "\n",
    "$$Attention(Q,K,V) = softmax\\left(M+\\frac{QK^T}{\\sqrt{d_k}}\\right)$$\n",
    "\n",
    "Where Q, K, V represent the Query, Key and Value Matrices, $d_k$ represents their dimension and $M$ is the Mask Matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a6eac692",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "import math\n",
    "\n",
    "def attention(q, k, v, d_k, mask=None, dropout=None):\n",
    "    scores = torch.matmul(q, k.transpose(-2, -1)) /  math.sqrt(d_k)\n",
    "    if mask is not None:\n",
    "        scores = scores.masked_fill(mask == 0, -1e9)\n",
    "    scores = F.softmax(scores, dim=-1)\n",
    "\n",
    "    if dropout is not None:\n",
    "        scores = dropout(scores)\n",
    "    \n",
    "    output = torch.matmul(scores, v)\n",
    "    return output\n",
    "\n",
    "class RTIDS_Multi_Head_Attention(nn.Module):\n",
    "    def __init__(self, heads, d_model, dropout):\n",
    "        super().__init__()\n",
    "        self.d_model = d_model\n",
    "        self.d_k = d_model // heads\n",
    "        self.h = heads\n",
    "        \n",
    "        self.q_linear = nn.Linear(d_model, d_model)\n",
    "        self.v_linear = nn.Linear(d_model, d_model)\n",
    "        self.k_linear = nn.Linear(d_model, d_model)\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.out = nn.Linear(d_model, d_model)\n",
    "    \n",
    "    def forward(self, q, k, v, mask=None):\n",
    "        \n",
    "        bs = q.size(0)\n",
    "        \n",
    "        # perform linear operation and split into h heads\n",
    "        k = self.k_linear(k).view(bs, -1, self.h, self.d_k)\n",
    "        q = self.q_linear(q).view(bs, -1, self.h, self.d_k)\n",
    "        v = self.v_linear(v).view(bs, -1, self.h, self.d_k)\n",
    "        \n",
    "        # transpose to get dimensions bs * h * sl * d_model\n",
    "        k = k.transpose(1,2)\n",
    "        q = q.transpose(1,2)\n",
    "        v = v.transpose(1,2)\n",
    "\n",
    "        scores = attention(q, k, v, self.d_k, mask, self.dropout)\n",
    "        \n",
    "        # concatenate heads and put through final linear layer\n",
    "        concat = scores.transpose(1,2).contiguous().view(bs, -1, self.d_model)\n",
    "        \n",
    "        output = self.out(concat)\n",
    "        return output\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42d42744",
   "metadata": {},
   "source": [
    "### Masks\n",
    "In Transformers, masks are typically used to prevent a Model form peeking ahead on the sequence it is supposed to generate during training. However, since RTIDS is not producing Sequences, the masking feature is used differently. Here we mask random Features in the input to make the model identify the truly important features in the sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a3d53bb5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import torch\n",
    "from torch.autograd import Variable\n",
    "\n",
    "def get_mask(batch_size, heads, seq_size):\n",
    "    mask_prob = 0.2\n",
    "    mask = torch.rand((batch_size, heads, seq_size, seq_size)) > mask_prob\n",
    "    return mask.cuda()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3c4efcd",
   "metadata": {},
   "source": [
    "### Feed-Forward Network\n",
    "As typical for Transformer Models, we add a Feed Forward Network in each Encoder and Decoder Layer. This Network consists of 2 Linear Layers, connected via a ReLU Function to obtain some non-linear Behaviour.\n",
    "$$FFN(x) = \\max(0,xW_1 + b_1)W_2 + b_2$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "74853cbd",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "\n",
    "class RTIDS_FeedForward(nn.Module):\n",
    "    def __init__(self, d_model, d_ff=1024, dropout = 0.1):\n",
    "        super().__init__() \n",
    "        self.linear_1 = nn.Linear(d_model, d_ff)\n",
    "        self.dropout = nn.Dropout(dropout)\n",
    "        self.linear_2 = nn.Linear(d_ff, d_model)\n",
    "    def forward(self, x):\n",
    "        x = self.dropout(F.relu(self.linear_1(x)))\n",
    "        x = self.linear_2(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d763249",
   "metadata": {},
   "source": [
    "### Layer Norm\n",
    "AS the last Building Block for the Transformer Model, I introduce the Layer Normalization. This Performs the following calculation to Normalize all Layer Outputs (And also the Outputs of the Encoder and Decoder).\n",
    "$$LN(x) = \\frac{x - \\mu}{\\delta}\\cdot \\alpha + \\beta$$\n",
    "Here, $\\mu$ denominates the Mean and $\\delta$ denominates the Standarddeviation of each Feature. $\\alpha$ and $\\beta$ describe trainable Parameters of this Layer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0737fbb5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "import torch\n",
    "\n",
    "class RTIDS_Norm(nn.Module):\n",
    "    def __init__(self, d_model, eps = 1e-6):\n",
    "        super().__init__()\n",
    "    \n",
    "        self.size = d_model\n",
    "        \n",
    "        self.alpha = nn.Parameter(torch.ones(self.size))\n",
    "        self.bias = nn.Parameter(torch.zeros(self.size))\n",
    "        self.eps = eps\n",
    "    def forward(self, x):\n",
    "        norm = self.alpha * (x - x.mean(dim=-1, keepdim=True)) \\\n",
    "        / (x.std(dim=-1, keepdim=True) + self.eps) + self.bias\n",
    "        return norm"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "055834d4",
   "metadata": {},
   "source": [
    "## Encoder Layer and Stack\n",
    "The Encoder Unit consists of 6 Encoder Layers, each of which consists of a Multi-Head Attention, followed by a Layer Normalization, then a Feed Forward Network and another Layer Normalization. We also introduce Recurrent Connections, so that some of the input Data surpasses the Attention and FFN Layers. This mainly serves two purposes: Firstly, it enables later layers to still learn from the original input and changes become incremental (Attention is arbitrary output, lacks local info). Secondly, During Backpropagation, the Gradient in Networks with as many layers as a Transformer will vanish due to ReLU and Dropout Layers. These Residual Connections ensure that the gradient will not fully vanish and the early Layers can still be trained.\n",
    "The Encoder Unit will also contain an Embedding and a Positional Encoding Unit before the first Encoder Layer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "153994f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "import copy\n",
    "\n",
    "def get_clones(module, N):\n",
    "    return nn.ModuleList([copy.deepcopy(module) for i in range(N)])\n",
    "\n",
    "class RTIDS_Encoder_Layer(nn.Module):\n",
    "    def __init__(self, d_model, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.norm_1 = RTIDS_Norm(d_model)\n",
    "        self.norm_2 = RTIDS_Norm(d_model)\n",
    "        self.attn = RTIDS_Multi_Head_Attention(heads, d_model, dropout)\n",
    "        self.feedf = RTIDS_FeedForward(d_model).cuda()\n",
    "        self.dropout_1 = nn.Dropout(dropout).cuda()\n",
    "        self.dropout_2 = nn.Dropout(dropout).cuda()\n",
    "\n",
    "    def forward(self, x, mask):\n",
    "        x2 = self.norm_1(x)\n",
    "        x = x + self.dropout_1(self.attn(x2,x2,x2,mask))\n",
    "        x2 = self.norm_2(x)\n",
    "        x = x + self.dropout_2(self.feedf(x2))\n",
    "        return x\n",
    "    \n",
    "class RTIDS_Encoder(nn.Module):\n",
    "    def __init__(self, d_model, N, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.N = N\n",
    "        self.embed = RTIDS_Embedder(d_model)\n",
    "        self.pe = RTIDS_Positional_Encoder(d_model)\n",
    "        self.layers = get_clones(RTIDS_Encoder_Layer(d_model, heads, dropout), N)\n",
    "        self.norm = RTIDS_Norm(d_model)\n",
    "\n",
    "    def forward(self, src, mask = None):\n",
    "        x = self.embed(src)\n",
    "        x = self.pe(x)\n",
    "        for i in range(self.N):\n",
    "            x = self.layers[i](x,mask)\n",
    "        return self.norm(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2320ca59",
   "metadata": {},
   "source": [
    "### Decoder Layer and Stack\n",
    "The Encoder Unit consists of 6 Encoder Layers, each of which consists of a Masked Multi-Head Attention, followed by a Layer Normalization, another Multi-Head Attention (This time with the encoder Outputs as the Value and Key inputs), another Layer Normalization, then a Feed Forward Network and another Layer Normalization. Just as we did for the Encoder, we also introduce the mentioned Residual connections around each of the Attention and FFN Layers.\n",
    "The Decpder Unit will also contain an Embedding and a Positional Encoding Unit before the first Decoder Layer and receive the same input as the Encoder Stack."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "05057eb8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "import copy\n",
    "\n",
    "def get_clones(module, N):\n",
    "    return nn.ModuleList([copy.deepcopy(module) for i in range(N)])\n",
    "\n",
    "class RTIDS_Decoder_Layer(nn.Module):\n",
    "    def __init__(self, d_model, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.norm_1 = RTIDS_Norm(d_model)\n",
    "        self.norm_2 = RTIDS_Norm(d_model)\n",
    "        self.norm_3 = RTIDS_Norm(d_model)\n",
    "        self.attn = RTIDS_Multi_Head_Attention(heads, d_model, dropout)\n",
    "        self.msk_attn = RTIDS_Multi_Head_Attention(heads, d_model, dropout)\n",
    "        self.feedf = RTIDS_FeedForward(d_model).cuda()\n",
    "        self.dropout_1 = nn.Dropout(dropout).cuda()\n",
    "        self.dropout_2 = nn.Dropout(dropout).cuda()\n",
    "        self.dropout_3 = nn.Dropout(dropout).cuda()\n",
    "\n",
    "    def forward(self, x, e_outputs, mask):\n",
    "        x2 = self.norm_1(x)\n",
    "        x = x + self.dropout_1(self.msk_attn(x2,x2,x2,mask))\n",
    "        x2 = self.norm_2(x)\n",
    "        x = x + self.dropout_2(self.attn(x2,e_outputs,e_outputs,mask=None))\n",
    "        x2 = self.norm_3(x)\n",
    "        x = x +self.dropout_3(self.feedf(x2))\n",
    "        return x\n",
    "\n",
    "class RTIDS_Decoder(nn.Module):\n",
    "    def __init__(self, d_model, N, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.N = N\n",
    "        self.embed = RTIDS_Embedder(d_model)\n",
    "        self.pe = RTIDS_Positional_Encoder(d_model,1)\n",
    "        self.layers = get_clones(RTIDS_Decoder_Layer(d_model, heads, dropout), N)\n",
    "        self.norm = RTIDS_Norm(d_model)\n",
    "\n",
    "    def forward(self, trg, e_outputs, mask = None):\n",
    "        x = self.embed(trg)\n",
    "        x = self.pe(x)\n",
    "        for i in range(self.N):\n",
    "            x = self.layers[i](x,e_outputs,mask)\n",
    "        return self.norm(x)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9695a1d8",
   "metadata": {},
   "source": [
    "### The RTIDS Transformer\n",
    "For the RTIDS Architecture, I use all the pieces described above to assemble a Transformer Model. However, this Transformer Model will spakŕk some differences to traditional generative Transformers, mainly the fact that this Model will not generate a Sequence of any kind, but rather just analyze a Sequence and output a single Class Token (\"Benign\" or \"Attack\"). Such classification Models are rather unusual in Transformer Archtiecture, since the Decoder unit is mainly used to be run multiple times to generate a sequence. Thus, the \"Encoder-Only\" Transformer Models have been developed specifically for classification tasks. In this Section I will introduce both the original RTIDS Transformer as well as an Encoder-Only Variant and will compare their Performance in the later sections."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "9bcfcd0c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "\n",
    "class RTIDS_Transformer(nn.Module):\n",
    "    def __init__(self, trg_vocab, d_model, N, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.encoder = RTIDS_Encoder(d_model, N , heads, dropout)\n",
    "        self.decoder = RTIDS_Decoder(d_model, N , heads, dropout)\n",
    "        self.out = nn.Linear(78*d_model, trg_vocab)\n",
    "    \n",
    "    def forward(self, src, trg_mask=None):\n",
    "        e_outputs = self.encoder(src, None)\n",
    "        d_output = self.decoder(src, e_outputs, trg_mask)\n",
    "        d_intermediate = d_output.view(d_output.size(0), -1)\n",
    "        output = self.out(d_intermediate)\n",
    "        output = torch.softmax(output,dim=1)\n",
    "        return output\n",
    "    \n",
    "class IDS_Encoder_Only(nn.Module):\n",
    "    def __init__(self, trg_vocab, d_model, N, heads, dropout = 0.1):\n",
    "        super().__init__()\n",
    "        self.encoder = RTIDS_Encoder(d_model, N, heads, dropout)\n",
    "        self.out = nn.Linear(78*d_model, trg_vocab)\n",
    "\n",
    "    def forward(self, src, _):\n",
    "        e_outputs = self.encoder(src, None)\n",
    "        e_intermediate = e_outputs.view(e_outputs.size(0),-1)\n",
    "        output = self.out(e_intermediate)\n",
    "        return torch.softmax(output, dim=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4dc38a33",
   "metadata": {},
   "source": [
    "## Data and Preprocessing"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ce19949",
   "metadata": {},
   "source": [
    "### CICIDS2017\n",
    "In the original RTIDS Paper bothe the CICIDS2017 and the CICIDS-DDoS2019 Datasets were introduced and used to train and test the models. For my observations I stuck to only using the CICIDS2017 Dataset as it provides some larger variations between different Attack types. As is already discussed in my Presentation, both of these Datasets are somewhat flawed (No PCAP-files, just summaries, many unimportant Features, only 6 Features make up most of the information, no real-time application) and are not perfectly suited for a proclaimed \"Real-Time\" Intrusion Detection System (see RTIDS Paper proposed Architecture).\n",
    "The CICIDS Dataset consists of 8 \\*.csv files, some containing faulty entries with missing labels or values, thus some preprocessing is required."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "488a1871",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "!mkdir -p data\n",
    "url = 'http://205.174.165.80/CICDataset/CIC-IDS-2017/Dataset/MachineLearningCSV.zip'\n",
    "zip_file_path = 'data/MachineLearningCSV.zip'\n",
    "!curl -o $zip_file_path $url\n",
    "!unzip -j $zip_file_path '*.csv' -d data\n",
    "!rm data/MachineLearningCSV.zip\n",
    "!ls data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8738b0aa",
   "metadata": {},
   "source": [
    "### Data Preprocessing\n",
    "Aside from the Problems mentioned above, the CICIDS2017 Datset suffers from a High Class Imbalance Rate, with more than 80 % of the Data being Benign traffic, while less than 0.01 % are Heartbleed Attacks. To tackle this particular issue, the authors of RTIDS employed SMOTE (Synthetic Minority Oversampling Technique), however its exact application contains some uncertainties:\n",
    "* There is no post-SMOTE information provided about the Dataset\n",
    "* It is unclear wether the Classes \"Benign\" and \"Attack\" have been balanced or all the classes\n",
    "\n",
    "As there is no clear information given, chose to set the sample sizes of all \"Attack\" Classes to 100.000 so that I can analyze the performance on all of these classes more or less equally and not have some too underrepresented to be analyzed. Furthermore I chose to set the size fr the \"Benign\" Class to 600.000. I did this so that the \"Attack\" class (which is all attack classes combined) is not much larger than the \"Benign\" class and the \"Benign\" Class is not too much larger than any one single Attack Class. Also this left me with exactly 2.000.000 samples.\n",
    "Further steps in the Data Preprocessing include Setting all Attack Labels to \"Attack\", removing faulty samples and Min-Max scaling all numeric features. In my personal Case, I had to employ incremental SMOTE on batches of size 10.000 as my RAM could not handle the full dataset being processed at once. I also had to use Undersampling to reduce the number of samples as the large Database size would also tend to crash my application."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "81d9c43e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import glob\n",
    "from sklearn.model_selection import train_test_split\n",
    "import torch\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import MinMaxScaler, LabelEncoder\n",
    "from sklearn.neighbors import NearestNeighbors\n",
    "from sklearn.utils import shuffle\n",
    "from imblearn.over_sampling import SMOTE\n",
    "from imblearn.under_sampling import RandomUnderSampler\n",
    "import os\n",
    "\n",
    "label_mapping = {}\n",
    "\n",
    "class CICIDSDataset(Dataset):\n",
    "    def __init__(self, data):\n",
    "        self.features = data[:, :-3]  # Feature Columns\n",
    "        self.at_type = data[:, -3] # Attack Type Column\n",
    "        self.labels = data[:, -2:]  # 1 Hot Encoded Label\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.labels)\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        feature = torch.from_numpy(self.features[idx]).float()\n",
    "        label = self.labels[idx]\n",
    "        at_type = self.at_type[idx]\n",
    "\n",
    "        return feature, label, at_type\n",
    "\n",
    "def load_data():\n",
    "    if os.path.exists(\"data/preprocessed/data.csv.gz\"):\n",
    "        print(\"Loading Preprocessed Data\")\n",
    "        data = pd.read_csv('data/preprocessed/data.csv.gz', compression='gzip')\n",
    "    \n",
    "    else:\n",
    "        directory_path = 'data/' # Path to the directory containing CICIDS 2017 dataset CSV files\n",
    "        csv_files = glob.glob(directory_path + '*.csv')\n",
    "\n",
    "        dataframes = []\n",
    "        for file in csv_files:\n",
    "            dataframe = pd.read_csv(file)\n",
    "            dataframes.append(dataframe)\n",
    "        data = pd.concat(dataframes, ignore_index=True)\n",
    "        data.columns = data.columns.str.strip()\n",
    "\n",
    "        data = data.dropna()\n",
    "        max_float64 = np.finfo(np.float64).max\n",
    "\n",
    "        features = data.drop('Label', axis=1)\n",
    "        features = features.where(features <= max_float64, max_float64)\n",
    "        labels = data['Label']\n",
    "        data = pd.concat([features, labels], axis=1)\n",
    "\n",
    "        # Undersampling & SMOTE\n",
    "\n",
    "        max_class_size = 100000 # Size of all Classes for Undersampling\n",
    "        class_counts = data['Label'].value_counts()\n",
    "        classes_to_undersample = class_counts[class_counts > max_class_size].index\n",
    "\n",
    "        under_sampler = RandomUnderSampler(sampling_strategy={\n",
    "                label: 7*max_class_size if label ==\"BENIGN\" else max_class_size if label in classes_to_undersample else class_counts[label] for label in np.unique(data['Label'])\n",
    "            }, random_state=42)\n",
    "        nn_estimator = NearestNeighbors(n_neighbors=5, n_jobs=-1)\n",
    "        smote = SMOTE(sampling_strategy={\n",
    "                label: 7*max_class_size if label ==\"BENIGN\" else max_class_size for label in np.unique(data['Label'])\n",
    "            }, k_neighbors=nn_estimator, random_state=42)\n",
    "        scaler = MinMaxScaler()\n",
    "\n",
    "        features = data.drop('Label', axis=1)\n",
    "        labels = data['Label']\n",
    "        sampled_features, sampled_labels = under_sampler.fit_resample(features, labels)\n",
    "        balanced_features, balanced_labels = smote.fit_resample(sampled_features, sampled_labels)\n",
    "        scaled_data = scaler.fit_transform(balanced_features)\n",
    "\n",
    "        data = pd.DataFrame(data=scaled_data, columns=features.columns)\n",
    "\n",
    "        # Encode the actual Attack type for later analysis\n",
    "        label_encoder = LabelEncoder()\n",
    "        data['Label'] = label_encoder.fit_transform(balanced_labels)\n",
    "        label_mapping = dict(enumerate(label_encoder.classes_))\n",
    "\n",
    "        # 1 Hot Encoding\n",
    "        data['Attack_Label'] = data['Label'].apply(lambda x: \"Attack\" if label_mapping[x] != \"BENIGN\" else \"BENIGN\")\n",
    "        encoded_labels = pd.get_dummies(data['Attack_Label'], prefix='', prefix_sep='')\n",
    "        data = pd.concat([data, encoded_labels], axis=1)\n",
    "        data.drop(\"Attack_Label\", axis=1, inplace=True)\n",
    "        \n",
    "        label_counts = data['Label'].value_counts()\n",
    "        print(label_counts)\n",
    "        if not os.path.exists('data/preprocessed'):\n",
    "            os.makedirs('data/preprocessed')\n",
    "        data.to_csv('data/preprocessed/data.csv.gz', index=False, compression='gzip')\n",
    "        print(\"saved\")\n",
    "\n",
    "    train_data, val_data = train_test_split(data, test_size=0.2, random_state=42)\n",
    "    train_data, val_data = train_data.values, val_data.values\n",
    "\n",
    "    return train_data, val_data\n",
    "\n",
    "def get_data_loader(data, batch_size):\n",
    "    cicids_dataset = CICIDSDataset(data)\n",
    "    \n",
    "    return DataLoader(cicids_dataset, batch_size=batch_size, shuffle=True)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d43198a5",
   "metadata": {},
   "source": [
    "## Training\n",
    "The Training is run with the Hyperparameters as stated in the original RTIDS Paper."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "7ba20b0a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torch.nn import functional as F\n",
    "import numpy as np\n",
    "import time\n",
    "import os\n",
    "\n",
    "def eval_model(model, loader):\n",
    "    model.cuda()\n",
    "    model.eval()\n",
    "    losses = []\n",
    "    correct = 0\n",
    "    with torch.no_grad():\n",
    "        for data, target, _ in loader:\n",
    "            data, target = data.to(\"cuda\"), target.to(\"cuda\")\n",
    "            output = model(data)\n",
    "            losses.append(F.cross_entropy(output, target).item())\n",
    "            correct += torch.eq(torch.argmax(output, dim=1),torch.argmax(target, dim=1)).cpu().sum().item()\n",
    "    eval_loss = float(np.mean(losses))\n",
    "    eval_acc = 100. * correct / len(loader.dataset)\n",
    "    print(\"Loss:\", eval_loss, \"Accuracy:\", eval_acc)\n",
    "    return eval_loss, eval_acc\n",
    "\n",
    "def train_model(model, opt, epochs, data, eval_data, path, print_every=100):\n",
    "    model.cuda()\n",
    "    \n",
    "    pretrained_path = \"pretrained\"\n",
    "    top_acc = 0.\n",
    "\n",
    "    if os.path.exists(pretrained_path + \"/\" + path):\n",
    "        print(\"Loading Pretrained Model\")\n",
    "        state = torch.load(pretrained_path + \"/\" + path)\n",
    "        model.load_state_dict(state[\"model_state_dict\"])\n",
    "        start_epoch = state[\"epoch\"] + 1\n",
    "        losses = state[\"ep_loss\"]\n",
    "        accs = state[\"ep_acc\"]\n",
    "        top_acc = max(accs)\n",
    "    else:\n",
    "        start_epoch = 0\n",
    "        losses, accs = [], []\n",
    "        try:\n",
    "            os.mkdir(pretrained_path)\n",
    "        except OSError as error:\n",
    "            pass \n",
    "\n",
    "    start = time.time()\n",
    "    temp = start\n",
    "    \n",
    "    for epoch in range(start_epoch, epochs):\n",
    "        model.train()\n",
    "        total_loss = 0\n",
    "        for i, batch in enumerate(data):\n",
    "            src,trg,_ = batch\n",
    "            src,trg = src.cuda(), trg.cuda()\n",
    "            \n",
    "            if isinstance(model,RTIDS_Transformer):\n",
    "                trg_mask = get_mask(128,8,78)\n",
    "            else:\n",
    "                trg_mask = None\n",
    "            \n",
    "            preds = model(src, trg_mask)            \n",
    "            opt.zero_grad()\n",
    "            loss = F.cross_entropy(preds, trg)\n",
    "            loss.backward()\n",
    "            opt.step()\n",
    "            \n",
    "            total_loss += loss.data \n",
    "            if (i + 1) % print_every == 0:\n",
    "                loss_avg = total_loss / print_every\n",
    "                print(\"time = %dm, epoch %d, iter = %d, loss = %.3f, \\\n",
    "                %ds per %d iters\" % ((time.time() - start) // 60, \n",
    "                epoch + 1, i + 1, loss_avg, time.time() - temp, \n",
    "                print_every))\n",
    "                total_loss = 0\n",
    "                temp = time.time()\n",
    "        ep_loss, ep_acc = eval_model(model,eval_data)\n",
    "\n",
    "        losses.append(ep_loss)\n",
    "        accs.append(ep_acc)\n",
    "        if ep_acc > top_acc:\n",
    "            top_state = {\n",
    "                \"model_state_dict\": model.state_dict(),\n",
    "                \"epoch\": epoch\n",
    "            }\n",
    "            torch.save(top_state, pretrained_path + \"/max_\" + path)\n",
    "        state = {\n",
    "                'model_state_dict': model.state_dict(),\n",
    "                'epoch': epoch,\n",
    "                'ep_loss': losses,\n",
    "                'ep_acc': accs\n",
    "            }\n",
    "        torch.save(state, pretrained_path + \"/\" + path)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f44fa028",
   "metadata": {},
   "source": [
    "In the following main training method you can change which model should be trained by (un)commenting either of the two lines (model AND save_path)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "88be5f2e",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn\n",
    "from torchsummary import summary\n",
    "\n",
    "def main():\n",
    "    learning_rate = 5e-4\n",
    "    batch_size = 128\n",
    "    epochs = 30\n",
    "    dropout_rate = 0.5\n",
    "    d_model = 32\n",
    "    heads = 8\n",
    "    N = 6\n",
    "    trg_vocab = 2    \n",
    "    \n",
    "    train_data, val_data = load_data()\n",
    "    \n",
    "    train_loader = get_data_loader(train_data, batch_size)\n",
    "    val_loader = get_data_loader(val_data, batch_size)\n",
    "\n",
    "    model = RTIDS_Transformer(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "    save_path = \"RTIDS_pretrained.pt\"\n",
    "#     model = IDS_Encoder_Only(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "#     save_path = \"pretrained_enc.pt\"\n",
    "\n",
    "    for p in model.parameters():\n",
    "        if p.dim() > 1:\n",
    "            nn.init.xavier_uniform_(p)\n",
    "    summary(model)\n",
    "    \n",
    "    optim = torch.optim.SGD(model.parameters(), lr=learning_rate)\n",
    "\n",
    "    train_model(model, optim, epochs, train_loader, val_loader, save_path)\n",
    "\n",
    "main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa3b40e4",
   "metadata": {},
   "source": [
    "## Model Evaluation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "595fac4b",
   "metadata": {},
   "source": [
    "### Training Comparison\n",
    "For this evaluation, each models accuracy and loss is analyzed after every epoch of training."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "a64eee6a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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iMguFWRWn8QAmuMFmSa5vEwmQ2BgoN7m5eWlOy4SifDll19izJgxcHZ2RvPmzbF79269Mi5cuIDhw4fD3d0dbm5u6NOnD1JSUgAAarUaixcvRuPGjSGTydCpUyfs3btX7/UnT55E586d4eTkhG7duuGPP/6oEGdSUhKGDh0KV1dXBAQE4B//+Afu3bunO/7YY49h1qxZmD17Nnx9fREVFVXp+3377beRmpqKAwcOYOjQoWjSpAn69u2Lffv2wdHREbGxsXplvvzyy3jjjTfg7e2NwMBALFq0qMrPcsCAAZg1a5bevrt370IqleLgwYNVvq4+mMhYmLafDMAaGSJqgIrzq95KioxbrgnFxcVh3LhxSExMxLBhwzBx4kTcv38fAHD79m307dsXMpkMhw4dwpkzZzBt2jSUlpYCAD799FN8/PHH+Oijj5CYmIioqCiMHDkSV69eBQDk5eVh+PDhaNOmDc6cOYNFixbhtdde07t+dnY2BgwYgM6dO+P06dPYu3cv7ty5g3Hjxumdt3HjRkilUvz2229Yt25dhfehVquxbds2TJw4EYGBgXrH5HI5XnzxRezbt0/33rRluri44MSJE1i+fDkWL16M/fv3V/o5Pffcc9iyZQuUyrLEdNOmTWjUqBEGDBhg6MddK2xasrBwv7IaGWWpCiq1wCXriajh+CC46mPNhwATt9et3BXtK9bQLMqpU1H//e9/4erqqrdv/vz5mD9/vu75lClTMGHCBADABx98gJUrV+LkyZOIjo7GmjVr4OHhgW3btsHRUVOz3qJFC91rP/roI7z55psYP348AGDZsmU4fPgwVqxYgTVr1mDLli1Qq9VYv349nJyc0LZtW9y6dQszZ87UlbF69Wp07twZH3zwgW7fhg0bEBISgj///FN3vebNm2P58uVVvte7d+8iOzsbrVu3rvR469atIQgCkpOT0aNHDwBAhw4dsHDhQl35q1evxsGDBzF48OAKrx87dixmzZqF77//XpdkffXVV7q+SKbARMaC9ialYfOJso5Vh6/cxaPLDmHhiDaIbhdkwciIiOxH//79sXbtWr193t7ees87dOige+zi4gJ3d3dkZGQAABISEtCnTx9dElOeQqFAamoqevfurbe/d+/eOHfuHADg0qVL6NChA5ycnHTHe/XqpXf+uXPncPjw4QoJFwCkpKToEpmuXbvW+H4BQBAEg84D9N87AAQFBene+8OcnJzwj3/8Axs2bMC4ceNw9uxZJCUlVWiKMyYmMhayNykNMzedxcNfpfScIszcdBZrn+nCZIaIbN/81KqPieox3cTs83V/7UNcXFzQrFmzas95OEkRiURQqzXzf8nlcqPFUpW8vDyMGDECy5Ytq3AsKKjsXuHi4lLheHl+fn7w9PTEpUuXKj1+6dIlzczz5T6P6t57ZZ577jl06tQJt27dQnx8PAYMGIDQ0NBq46oP9pGxAJVaQNyeixWSGAC6fXF7LkKlNjxjJiKySlKXqjdHp5pfX5tyLaRDhw745ZdfUFJSUuGYu7s7goOD8dtvv+nt/+2339CmTRsAmuacxMREFBWV9Rk6fvy43vldunTBhQsX0LRpUzRr1kxvqyl5KU8sFmPcuHHYsmUL0tPT9Y4VFhbis88+Q1RUVIUaqdpo3749unXrhi+++AJbtmzBtGnT6lyWIZjIWMDJa/eRllN1JzcBQFpOEU5eu1/lOUREZBxKpRLp6el6W/nRQDWZNWsWFAoFxo8fj9OnT+Pq1av497//jStXrgAAXn/9dSxbtgzffPMNrly5grfeegsJCQl45ZVXAABPP/00RCIRnn/+eVy8eBH/+9//8NFHH+ldIzY2Fvfv38eECRNw6tQppKSkYN++fZg6dSpUKlWt3u8HH3yAwMBADB48GD/++CNu3ryJo0ePIioqCiUlJVizZk2tyqvMc889hw8//BCCIGDMmDH1Lq86Fk1kFi1aVGESolatWumOP/bYYxWOz5gxw4IRG0dGrmE99Q09j4jIpjn7aOaJqY6DTHOeCezduxdBQUF626OPPmrw6318fHDo0CHk5eWhX79+6Nq1K7744gtdk8zLL7+MuXPn4tVXX0X79u2xd+9e7N69G82bNwcAuLq6Ys+ePTh//jw6d+6Mt99+u0ITkrZWR6VSYciQIWjfvj1mz54NT09PiMW1u5X7+Pjg+PHj6N+/P1544QVERERg3LhxiIiIwKlTp4wyh8yECRPg4OCACRMm6PX9MQWRUJseP0a2aNEifPvttzhw4IBun4ODA3x9fQFoEpkWLVpg8eLFuuPOzs5wd3c3+BoKhQIeHh7Iycmp1etM6VhKJiZ8cbzG87Y+3xO9IkzzH5eIyFiKiopw7do1hIWF1f2mlX2z+nlinH1MMhkemcb169d1iVGXLl2qPK+6746h92+Ld/Z1cHCoMJa9PGdn52qP26IeYd4I8nBCek5Rpf1kRAACPZzQI6zubZRERDbFM4SJSgNQUlKCzMxMLFiwAD179qw2iTEWi/eRuXr1KoKDgxEeHo6JEydWWOdh8+bN8PX1Rbt27TBv3jwUFBRUW55SqYRCodDbrI1ELMLCEZpOXg+Pqtc+XziiDeeTISIim/Lbb78hKCgIp06dqnRCPlOwaI1MZGQkvvrqK7Rs2RJpaWmIi4tDnz59kJSUBDc3Nzz99NMIDQ1FcHAwEhMT8eabb+LKlSvYsWNHlWUuXboUcXFxZnwXdRPdLghrn+mCuD0X9Tr+Bno4cR4ZIiKySY899lit5qgxBov2kXlYdnY2QkND8cknn+DZZ5+tcPzQoUMYOHAgkpOTERERUWkZSqVSb2pkhUKBkJAQq+ojU55KLeDktfvIyC2Cv5umOYk1MURkS4zSR4bsUoPoI1Oep6cnWrRogeTk5EqPR0ZGAkC1iYxMJrOpVUslYhE79BIREdWRxfvIlJeXl4eUlBS9WQrLS0hIAIAqjxMRkeVYUQU/2QhjfGcsWiPz2muvYcSIEQgNDUVqaioWLlwIiUSCCRMmICUlBVu2bMGwYcPg4+ODxMREzJkzB3379q2w7gMREVmOdr6UgoICs0zXTw2HdgBPZetUGcqiicytW7cwYcIEZGZmws/PD48++iiOHz8OPz8/FBUV4cCBA1ixYgXy8/MREhKCmJgYLFiwwJIhExHRQyQSCTw9PXULCTo7O5tspWNqGARBQEFBATIyMuDp6QmJpO7rbllVZ19TsMYJ8YiIGhpBEJCeno7s7GxLh0I2xNPTE4GBgZUmvjbZ2ZeIiGyTSCRCUFAQ/P39K108kehhjo6O9aqJ0WIiQ0RERiORSIxycyIylFWNWiIiIiKqDSYyREREZLOYyBAREZHNavB9ZLSDsqxx8UgiIiKqnPa+XdPg6gafyOTm5gIAQkK4PDwREZGtyc3NhYeHR5XHG/w8Mmq1GqmpqXBzc4NIJNItInnz5k3OK2NG/Nwtg5+7+fEztwx+7pZhys9dEATk5uYiODgYYnHVPWEafI2MWCxG48aNK+x3d3fnl90C+LlbBj938+Nnbhn83C3DVJ97dTUxWuzsS0RERDaLiQwRERHZLLtLZGQyGRYuXAiZTGbpUOwKP3fL4OdufvzMLYOfu2VYw+fe4Dv7EhERUcNldzUyRERE1HAwkSEiIiKbxUSGiIiIbBYTGSIiIrJZdpXIrFmzBk2bNoWTkxMiIyNx8uRJS4fUoC1atAgikUhva9WqlaXDanCOHj2KESNGIDg4GCKRCLt27dI7LggC3n33XQQFBUEul2PQoEG4evWqZYJtQGr63KdMmVLh+x8dHW2ZYBuQpUuXonv37nBzc4O/vz9Gjx6NK1eu6J1TVFSE2NhY+Pj4wNXVFTExMbhz546FIm4YDPncH3vssQrf+RkzZpg8NrtJZL755hvMnTsXCxcuxNmzZ9GxY0dERUUhIyPD0qE1aG3btkVaWppu+/XXXy0dUoOTn5+Pjh07Ys2aNZUeX758OVauXIl169bhxIkTcHFxQVRUFIqKiswcacNS0+cOANHR0Xrf/61bt5oxwobp559/RmxsLI4fP479+/ejpKQEQ4YMQX5+vu6cOXPmYM+ePdi+fTt+/vlnpKamYuzYsRaM2vYZ8rkDwPPPP6/3nV++fLnpgxPsRI8ePYTY2Fjdc5VKJQQHBwtLly61YFQN28KFC4WOHTtaOgy7AkDYuXOn7rlarRYCAwOF//u//9Pty87OFmQymbB161YLRNgwPfy5C4IgTJ48WRg1apRF4rEnGRkZAgDh559/FgRB8/12dHQUtm/frjvn0qVLAgDh2LFjlgqzwXn4cxcEQejXr5/wyiuvmD0Wu6iRKS4uxpkzZzBo0CDdPrFYjEGDBuHYsWMWjKzhu3r1KoKDgxEeHo6JEyfixo0blg7Jrly7dg3p6el6330PDw9ERkbyu28GR44cgb+/P1q2bImZM2ciMzPT0iE1ODk5OQAAb29vAMCZM2dQUlKi951v1aoVmjRpwu+8ET38uWtt3rwZvr6+aNeuHebNm4eCggKTx9LgF40EgHv37kGlUiEgIEBvf0BAAC5fvmyhqBq+yMhIfPXVV2jZsiXS0tIQFxeHPn36ICkpCW5ubpYOzy6kp6cDQKXffe0xMo3o6GiMHTsWYWFhSElJwfz58zF06FAcO3YMEonE0uE1CGq1GrNnz0bv3r3Rrl07AJrvvFQqhaenp965/M4bT2WfOwA8/fTTCA0NRXBwMBITE/Hmm2/iypUr2LFjh0njsYtEhixj6NChuscdOnRAZGQkQkND8Z///AfPPvusBSMjMr3x48frHrdv3x4dOnRAREQEjhw5goEDB1owsoYjNjYWSUlJ7HtnZlV97tOnT9c9bt++PYKCgjBw4ECkpKQgIiLCZPHYRdOSr68vJBJJhV7rd+7cQWBgoIWisj+enp5o0aIFkpOTLR2K3dB+v/ndt7zw8HD4+vry+28ks2bNwn//+18cPnwYjRs31u0PDAxEcXExsrOz9c7nd944qvrcKxMZGQkAJv/O20UiI5VK0bVrVxw8eFC3T61W4+DBg+jVq5cFI7MveXl5SElJQVBQkKVDsRthYWEIDAzU++4rFAqcOHGC330zu3XrFjIzM/n9rydBEDBr1izs3LkThw4dQlhYmN7xrl27wtHRUe87f+XKFdy4cYPf+Xqo6XOvTEJCAgCY/DtvN01Lc+fOxeTJk9GtWzf06NEDK1asQH5+PqZOnWrp0Bqs1157DSNGjEBoaChSU1OxcOFCSCQSTJgwwdKhNSh5eXl6f/Fcu3YNCQkJ8Pb2RpMmTTB79mwsWbIEzZs3R1hYGN555x0EBwdj9OjRlgu6Aajuc/f29kZcXBxiYmIQGBiIlJQUvPHGG2jWrBmioqIsGLXti42NxZYtW/D999/Dzc1N1+/Fw8MDcrkcHh4eePbZZzF37lx4e3vD3d0dL730Enr16oWePXtaOHrbVdPnnpKSgi1btmDYsGHw8fFBYmIi5syZg759+6JDhw6mDc7s46QsaNWqVUKTJk0EqVQq9OjRQzh+/LilQ2rQnnrqKSEoKEiQSqVCo0aNhKeeekpITk62dFgNzuHDhwUAFbbJkycLgqAZgv3OO+8IAQEBgkwmEwYOHChcuXLFskE3ANV97gUFBcKQIUMEPz8/wdHRUQgNDRWef/55IT093dJh27zKPnMAQnx8vO6cwsJC4cUXXxS8vLwEZ2dnYcyYMUJaWprlgm4Aavrcb9y4IfTt21fw9vYWZDKZ0KxZM+H1118XcnJyTB6b6EGARERERDbHLvrIEBERUcPERIaIiIhsFhMZIiIisllMZIiIiMhmMZEhIiIim8VEhoiIiGwWExkiIiKyWUxkiMjuiEQi7Nq1y9JhEJERMJEhIrOaMmUKRCJRhS06OtrSoRGRDbKbtZaIyHpER0cjPj5eb59MJrNQNERky1gjQ0RmJ5PJEBgYqLd5eXkB0DT7rF27FkOHDoVcLkd4eDi+/fZbvdefP38eAwYMgFwuh4+PD6ZPn468vDy9czZs2IC2bdtCJpMhKCgIs2bN0jt+7949jBkzBs7OzmjevDl2795t2jdNRCbBRIaIrM4777yDmJgYnDt3DhMnTsT48eNx6dIlAEB+fj6ioqLg5eWFU6dOYfv27Thw4IBeorJ27VrExsZi+vTpOH/+PHbv3o1mzZrpXSMuLg7jxo1DYmIihg0bhokTJ+L+/ftmfZ9EZAQmX5aSiKicyZMnCxKJRHBxcdHb3n//fUEQNKvszpgxQ+81kZGRwsyZMwVBEITPP/9c8PLyEvLy8nTHf/jhB0EsFutWlw4ODhbefvvtKmMAICxYsED3PC8vTwAg/Pjjj0Z7n0RkHuwjQ0Rm179/f6xdu1Zvn7e3t+5xr1699I716tULCQkJAIBLly6hY8eOcHFx0R3v3bs31Go1rly5ApFIhNTUVAwcOLDaGDp06KB77OLiAnd3d2RkZNT1LRGRhTCRISKzc3FxqdDUYyxyudyg8xwdHfWei0QiqNVqU4RERCbEPjJEZHWOHz9e4Xnr1q0BAK1bt8a5c+eQn5+vO/7bb79BLBajZcuWcHNzQ9OmTXHw4EGzxkxElsEaGSIyO6VSifT0dL19Dg4O8PX1BQBs374d3bp1w6OPPorNmzfj5MmTWL9+PQBg4sSJWLhwISZPnoxFixbh7t27eOmll/CPf/wDAQEBAIBFixZhxowZ8Pf3x9ChQ5Gbm4vffvsNL730knnfKBGZHBMZIjK7vXv3IigoSG9fy5YtcfnyZQCaEUXbtm3Diy++iKCgIGzduhVt2rQBADg7O2Pfvn145ZVX0L17dzg7OyMmJgaffPKJrqzJkyejqKgI//znP/Haa6/B19cXTzzxhPneIBGZjUgQBMHSQRARaYlEIuzcuROjR4+2dChEZAPYR4aIiIhsFhMZIiIislnsI0NEVoWt3URUG6yRISIiIpvFRIaIiIhsFhMZIiIisllMZIiIiMhmMZEhIiIim8VEhoiIiGwWExkiIiKyWUxkiIiIyGYxkSEiIiKb9f8kKx2FJ/D3rgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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WzfRyclJVKvVYlhYmPjFF1+YXd7ExETxscceEwMCAkR7e3vR3d1dHD58uLh582aTYez5+fni/Pnzjek6d+4srlixQtTr9Sb5ARCjo6NN9hmG01cePr9//34RgPjll18a991///1ijx49xD/++EMMDw8XVSqVGBQUJK5atcrkXL1eL7711ltiUFCQqFQqxX79+onfffedOGXKFDEoKKjOa99+zDDMvz7Pc9WqVWK3bt1Ee3t70dfXV5w1a5Z448YNkzSGe6mschmJWgNBFNnzjoiooYYMGYLs7GybXeaEqLViHyQiIiKiShggEREREVXCAImIiIioEvZBIiIiIqqENUhERERElTBAIiIiIqqEE0U2kF6vR3p6OlxcXKos7EhERETNkyiKyM/PR0BAAGSymuuJGCA1UHp6epWVvomIiKhluHz5Mtq2bVvjcQZIDeTi4gJAesCGdaiIiIioedNqtQgMDDT+jteEAVIDGZrVXF1dGSARERG1MHV1j2EnbSIiIqJKGCARERERVcIAiYiIiKgS9kEiIqJmT6fToayszNrFoBbA3t4ecrm80fkwQCIiomZLFEVoNBrk5uZauyjUgri5ucHPz69R8xQyQCIiombLEBz5+PjA0dGRE/NSrURRRFFRETIzMwEA/v7+Dc6LARIRETVLOp3OGBx5enpauzjUQjg4OAAAMjMz4ePj0+DmNnbSJiKiZsnQ58jR0dHKJaGWxvCdaUy/NQZIRETUrLFZjerLEt8ZNrHZKJ1exNGLOcjML4aPiwoD23tALuM/MkREROZggGSD4k5ew5JvT+NaXrFxn79ahUWjQhDVs+Ed1oiIiFoLNrHZmLiT1zDrs2MmwREAaPKKMeuzY4g7ec1KJSMisg6dXkRCynXsTLqKhJTr0OnFJr/m1KlTIQgCBEGAvb092rdvj5deeglr1qwx7q9pS01NxeLFi9G3b19jfosXLzYet7Ozg5eXFwYPHoyVK1eipKTE5NoXL17EY489hoCAAKhUKrRt2xajR4/G2bNnm/y+bQlrkGyITi9iybenUd1ffRGAAGDJt6fxQIgfm9uIqFWwZo16VFQUNm7ciLKyMiQmJmLKlCl45plncO1axX9Ux44di549e2Lp0qXGfd7e3tXm16NHD/z000/Q6/W4fv06Dhw4gGXLluF///sfDhw4ABcXF5SVleGBBx5A165d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VHvNkpISaLVak61ZunQI2PMCcOzTBp3OTtpERERWDpCys7Oh0+ng6+trst/X1xcajabac7p27YoNGzZg586d+Oyzz6DX6zFo0CBcuXLFmCYqKgqffvop4uPjsXz5cvz8888YOXIkdDodAECj0VRpvrOzs4OHh0eN142NjYVarTZugYGBjbn1pmOh2bSz2cRGREStmNWb2OorPDwc4eHhxs+DBg1C9+7dsXbtWrz55psAgEcffdR4vFevXujduzc6duyIAwcOYPjw4Q267oIFCxATE2P8rNVqm2eQZAiQ8i4DoghU0z+rNhWdtKXlRqrr30VERGTrrFqD5OXlBblcjoyMDJP9GRkZdfYxMrC3t0e/fv1w/vz5GtN06NABXl5exjR+fn7IzMw0SVNeXo6cnJwar6tUKuHq6mqyNUvqttJrWRFQdL32tNUwNLGV6vTQFnO5ESIiap2sGiApFAqEhoYiPj7euE+v1yM+Pt6klqg2Op0OJ06cgL+/f41prly5guvXrxvThIeHIzc3F4mJicY0+/btg16vR1hYWAPvppmwUwIut55FA5rZVPZyuBiWG2EzGxERtVJWnwcpJiYG69atw+bNm3HmzBnMmjULhYWFxlFtkydPxoIFC4zply5dih9//BEXLlzAsWPH8Pjjj+PSpUt46qmnAEgduF988UUcPnwYqampiI+Px+jRo9GpUydERkYCALp3746oqCjMmDEDR48excGDBzF79mw8+uijLXsEm0Ej+yFxskgiImrtGtQH6fLlyxAEAW3bSs05R48exdatWxESEoKZM2fWK68JEyYgKysLCxcuhEajQd++fREXF2fsuJ2WlgaZrCKOu3HjBmbMmAGNRgN3d3eEhobi0KFDCAkJAQDI5XIcP34cmzdvRm5uLgICAjBixAi8+eabJnMhbdmyBbNnz8bw4cMhk8kwbtw4fPDBBw15HM2POhC4fKThHbWdlbiQXcgAiYiIWi1BFEWxvifdd999mDlzJp544gloNBp07doVPXr0wLlz5zBnzhwsXLiwKcrarGi1WqjVauTl5TW//kiaE0BpEeDVGXD0qPfpz25JxJ4TGiweFYKp97RvggISERFZh7m/3w1qYjt58iQGDhwIAPjiiy/Qs2dPHDp0CFu2bMGmTZsaVGCyIL9e0nIjDQiOAE4WSURE1KAAqayszNhc9dNPP+Gh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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import torch\n",
    "import os\n",
    "\n",
    "rtids_path = \"pretrained/RTIDS_pretrained.pt\"\n",
    "encon_path = \"pretrained/pretrained_enc.pt\"\n",
    "\n",
    "def analyze():\n",
    "    rtids_acc = []\n",
    "    rtids_los = []\n",
    "    if os.path.exists(rtids_path):\n",
    "        state_rtids = torch.load(rtids_path)\n",
    "        rtids_acc = state_rtids[\"ep_acc\"]\n",
    "        rtids_loss = state_rtids[\"ep_loss\"]\n",
    "    \n",
    "    encon_acc = []\n",
    "    encon_los = []\n",
    "    if os.path.exists(encon_path):\n",
    "        state_encon = torch.load(encon_path)\n",
    "        encon_acc = state_encon[\"ep_acc\"]\n",
    "        encon_loss = state_encon[\"ep_loss\"]\n",
    "\n",
    "    rtids_x_values = list(range(1, len(rtids_acc) + 1))\n",
    "    encon_x_values = list(range(1, len(encon_acc) + 1))\n",
    "\n",
    "    plt.figure(1)\n",
    "    plt.plot(rtids_x_values, rtids_acc, label='RTIDS', marker='o', linestyle='-')\n",
    "    plt.plot(encon_x_values, encon_acc, label='Encoder Only', marker='s', linestyle='--')\n",
    "\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.ylabel('Accuracy')\n",
    "    plt.title('Accuracy Comparison')\n",
    "    plt.legend()\n",
    "    plt.show()\n",
    "\n",
    "    plt.figure(2)\n",
    "    plt.plot(rtids_x_values, rtids_loss, label='RTIDS', marker='o', linestyle='-')\n",
    "    plt.plot(encon_x_values, encon_loss, label='Encoder Only', marker='s', linestyle='--')\n",
    "\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.ylabel('Loss')\n",
    "    plt.title('Loss Comparison')\n",
    "    plt.legend()\n",
    "    plt.show()\n",
    "\n",
    "    \n",
    "analyze()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52588019",
   "metadata": {},
   "source": [
    "As evident in the Diagrams, the RTIDS model achieves a maximum Accuracy of around 87% after 25 Epochs. Noticably, after epoch 2, the model performance drops off significantly before increasing again after epoch 3. Beginning after epoch 10, the model achieves 85% Accuracy with only minimal increases afterwards.\n",
    "\n",
    "The Encoder Only Model achieves a maximum Accuracy of roughly 85% after epoch 25, with only minimal increases after epoch 4."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8878145f",
   "metadata": {},
   "source": [
    "### Model Performance\n",
    "In this Part I will analyze the Accuracy of each model per Class. It is important to note that this analysis is not using the furthest trained state of the models, but rather the state with the highest accuracy during training. On the most recent set of training data, this happens to be after 25 epochs, on older version, sometimes the performance dropped off after 15 to 20 epochs, presumably due to overfitting.\n",
    "\n",
    "It is important to note, that the results of this analysis must be taken with a grain of salt, since the model does not actually differentiate between the different attack types. However it helps to visualize which attack classes can succesfully be identified as an attack and which seem to pose problems for the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "23c777ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{}\n"
     ]
    },
    {
     "data": {
      "image/png": "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75Z08R/Y8uXL27z+97//6ciRI4Ua97/5+vpKuji341rl5eXpnXfeUWRkpNzd3VWuXDmVL19eW7dute5LSRo2bJi8vb111113KTIyUrGxsfrpp59s1jVp0iRt375doaGhuuuuuzRmzJir/kNa1DHs379fTk5O+X42QUFBKl26tPbv32/T/u+g6+fnJ0kKDQ0tsP3fc62cnJxUqVIlm7bbb79dkqw/X0latmyZGjVqJA8PD5UtW1bly5fXzJkzbfbhJREREVcbpqSr789LY61atWq+z1arVi3fvvDw8FD58uVt2sqUKVPg/DLcWgg7MK2VK1fqr7/+0oIFCxQZGWl9denSRZIuO1H5elzuCM/lJkj+86jDP/u2adNG33zzjYYNG6YlS5YoMTHROrk5Ly+vyHX17NlTa9as0aFDh7Rnzx798ssvhT6qUxiXavr444+VmJiY7/XVV1/Z9C9o3AXx9fVVSEiItm/ffs21jR8/XkOGDNHdd9+tTz75RN99950SExNVs2ZNm31ZvXp1paSkaMGCBWrWrJm+/PJLNWvWzObKvS5dumjv3r2aNm2aQkJC9Oabb6pmzZr69ttv7T6Gwh4tdHZ2LlK78a+Jx4Xxww8/6KGHHpKHh4fee+89/fe//1ViYqIeffTRAtf3z6NAV3It+/NKLjdmgAnKMK158+YpICBAM2bMyLds0aJFWrx4sWbNmiVPT09Vrlz5qv8YVa5cWUlJScrJybE5pfNPZcqUkXTxyq5/+vdfoFeybds2/f7775o7d6569uxpbU9MTLTpd+mv8cL8I9qtWzcNGTJEn376qc6dOydXV1d17dq10DXt3r3beipQujih+6+//tKDDz4oSdbJ2QEBAWrdunWh11sYbdu21ezZs7Vu3bpCTab+ty+++EItW7bUnDlzbNozMjJUrlw5mzYvLy917dpVXbt2VXZ2tjp06KBx48ZpxIgR1tMowcHBevbZZ/Xss8/qyJEjqlu3rsaNG6cHHnjALmMICwtTXl6edu/ererVq1vb09PTlZGRobCwsKLugivKy8vT3r17rUdzJOn333+XJOvE4i+//FIeHh767rvv5O7ubu0XHx9/3du/0v68NNaUlBS1atXK5nMpKSl23xcwL47swJTOnTunRYsWqW3bturUqVO+V1xcnE6dOqWlS5dKkjp27KgtW7YUeIn2pb9cO3bsqGPHjmn69OmX7RMWFiZnZ2etXbvWZvl7771X6Nov/XX6z7+YDcPQu+++a9OvfPnyuvvuu/Xhhx/qwIEDBdZzSbly5fTAAw/ok08+0bx583T//ffn+4f+SmbPnq2cnBzr+5kzZ+rChQvWf+Cjo6Pl6+ur8ePH2/S75OjRo4Xe1r+9+OKL8vLy0pNPPqn09PR8y/fs2ZNv3/yTs7Nzvv3x+eef57t0+e+//7Z57+bmpho1asgwDOXk5Cg3NzffKZuAgACFhITkuyT8esZwKUBOmTLFps/bb78tSfmufLKHf36nDcPQ9OnT5erqqnvvvVfSxX1osVhsjlDu27dPS5YsueZtFmZ/1q9fXwEBAZo1a5bNPv7222+1a9euYtkXMCeO7MCUli5dqlOnTumhhx4qcHmjRo1Uvnx5zZs3T127dtXQoUP1xRdfqHPnzurbt6/q1aun48ePa+nSpZo1a5Zq166tnj176qOPPtKQIUO0fv16NW/eXGfOnNH333+vZ599Vg8//LD8/PzUuXNnTZs2TRaLRZUrV9ayZcvyzVm5kmrVqqly5cp64YUX9Oeff8rX11dffvllgfMOpk6dqmbNmqlu3brq16+fIiIitG/fPn3zzTdKTk626duzZ0916tRJkvTaa68VfmdKys7O1r333mu9dPm9995Ts2bNrPvX19dXM2fO1OOPP666deuqW7duKl++vA4cOKBvvvlGTZs2LTAkFkblypU1f/58de3aVdWrV7e5+/DPP/+szz///IrPwmrbtq3Gjh2rPn36qEmTJtq2bZvmzZuXb57Kfffdp6CgIDVt2lSBgYHatWuXpk+frpiYGPn4+CgjI0MVKlRQp06dVLt2bXl7e+v777/Xhg0b9NZbb9ltDLVr11avXr00e/ZsZWRkqEWLFlq/fr3mzp2r9u3b2xxhswcPDw8tX75cvXr1UsOGDfXtt9/qm2++0ciRI63zX2JiYvT222/r/vvv16OPPqojR45oxowZqlKlirZu3XpN2z116tRV96erq6smTpyoPn36qEWLFurevbv10vPw8HANHjzYbvsBJuegq8CAYtWuXTvDw8PDOHPmzGX79O7d23B1dTWOHTtmGIZh/P3330ZcXJxx2223GW5ubkaFChWMXr16WZcbxsXLb1966SUjIiLCcHV1NYKCgoxOnToZe/bssfY5evSo0bFjR6NUqVJGmTJljKefftrYvn17gZeee3l5FVjbzp07jdatWxve3t5GuXLljKeeesrYsmVLvnUYhmFs377deOSRR4zSpUsbHh4eRtWqVY1Ro0blW2dWVpZRpkwZw8/Pz+Yy3iu5dOn5mjVrjH79+hllypQxvL29jR49ehh///13vv6rVq0yoqOjDT8/P8PDw8OoXLmy0bt3b2Pjxo2FGveV/P7778ZTTz1lhIeHG25uboaPj4/RtGlTY9q0acb58+et/Qq69Pz55583goODDU9PT6Np06bGunXrjBYtWhgtWrSw9nv//feNu+++2/D39zfc3d2NypUrG0OHDjVOnjxpGMbF/Td06FCjdu3aho+Pj+Hl5WXUrl3beO+99+w+hpycHOPVV1+1fs9CQ0ONESNG2PS5NNaYmJh825GU75LuS7c/ePPNN61tl34We/bsMe677z6jVKlSRmBgoDF69Oh8l+vPmTPHiIyMNNzd3Y1q1aoZ8fHxxujRo41//zNS0Lb/uezSpedF2Z8LFy406tSpY7i7uxtly5Y1evToYRw6dMimz+W+VwXViFuPxTCuYbYagJvOhQsXFBISonbt2uWbv3I5l27otmHDBtWvX7+YK8SN1rt3b33xxRc6ffq0o0sBihVzdoBbxJIlS3T06FGbSc8AcCtgzg5gcklJSdq6datee+011alTx3q/HgC4VXBkBzC5mTNnqn///goICNBHH33k6HIA4IZzaNhZu3at2rVrp5CQEFkslnyXMRqGoVdeeUXBwcHy9PRU69atrXdqveT48ePq0aOHfH19Vbp0aT3xxBOcfwb+ISEhQRcuXNDGjRuverflf+vdu7cMw2C+jkklJCTw+xK3BIeGnTNnzqh27doF3vRNungr8alTp2rWrFlKSkqSl5eXoqOjdf78eWufHj16aMeOHUpMTNSyZcu0du1a9evX70YNAQAAlHAl5mosi8WixYsXq3379pIuHtUJCQnR888/rxdeeEHSxWcCBQYGKiEhQd26ddOuXbtUo0YNmytFli9frgcffFCHDh1SSEiIo4YDAABKiBI7QTk1NVVpaWk2t5738/NTw4YNtW7dOnXr1k3r1q1T6dKlbQ6xt27dWk5OTkpKSirwCdaSlJWVZXM3zry8PB0/flz+/v7X9fRqAABw4xiGoVOnTikkJOSKz9srsWEnLS1NkhQYGGjTHhgY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OnXUr18/PfXUU5o1a9Z1rXfEiBE6efKk9XXw4EE7VQwAAEqaEh12goODVaNGDZu26tWr68CBA5KkoKAgSVJ6erpNn/T0dOuygri7u8vX19fmBQAAzKlEh52mTZsqJSXFpu33339XWFiYpIuTlYOCgrRixQrr8szMTCUlJalx48Y3tFYAAFAyleirsQYPHqwmTZpo/Pjx6tKli9avX6/Zs2dr9uzZkiSLxaJBgwbp9ddfV2RkpCIiIjRq1CiFhISoffv2ji0eAACUCCU67DRo0ECLFy/WiBEjNHbsWEVERGjKlCnq0aOHtc+LL76oM2fOqF+/fsrIyFCzZs20fPlyeXh4OLByAABQUpTosCNJbdu2Vdu2bS+73GKxaOzYsRo7duwNrAoAANwsSvScHQAAgOtV5LATHh6usWPHWq+IAgAAKMmKHHYGDRqkRYsWqVKlSmrTpo0WLFigrKys4qgNAADgul1T2ElOTtb69etVvXp1PffccwoODlZcXJw2b95cHDUCAABcs2ues1O3bl1NnTpVhw8f1ujRo/Wf//xHDRo00J133qkPP/xQhmHYs04AAIBrcs1XY+Xk5Gjx4sWKj49XYmKiGjVqpCeeeEKHDh3SyJEj9f3332v+/Pn2rBUAAKDIihx2Nm/erPj4eH366adycnJSz5499c4776hatWrWPo888ogaNGhg10IBAACuRZHDToMGDdSmTRvNnDlT7du3l6ura74+ERER6tatm10KBAAAuB5FDjt79+61Ppvqcry8vBQfH3/NRQEAANhLkScoHzlyRElJSfnak5KStHHjRrsUBQAAYC9FDjuxsbE6ePBgvvY///xTsbGxdikKAADAXoocdnbu3Km6devma69Tp4527txpl6IAAADspchhx93dXenp6fna//rrL7m4lPjnigIAgFtMkcPOfffdpxEjRujkyZPWtoyMDI0cOVJt2rSxa3EAAADXq8iHYiZPnqy7775bYWFhqlOnjiQpOTlZgYGB+vjjj+1eIAAAwPUocti57bbbtHXrVs2bN09btmyRp6en+vTpo+7duxd4zx0AAABHuqZJNl5eXurXr5+9awEAALC7a55RvHPnTh04cEDZ2dk27Q899NB1FwUAAGAv13QH5UceeUTbtm2TxWKxPt3cYrFIknJzc+1bIQAAwHUo8tVYAwcOVEREhI4cOaJSpUppx44dWrt2rerXr6/Vq1cXQ4kAAADXrshHdtatW6eVK1eqXLlycnJykpOTk5o1a6YJEyZowIAB+vXXX4ujTgAAgGtS5CM7ubm58vHxkSSVK1dOhw8fliSFhYUpJSXFvtUBAABcpyIf2alVq5a2bNmiiIgINWzYUJMmTZKbm5tmz56tSpUqFUeNAAAA16zIYefll1/WmTNnJEljx45V27Zt1bx5c/n7+2vhwoV2LxAAAOB6FDnsREdHW/+7SpUq+u2333T8+HGVKVPGekUWAABASVGkOTs5OTlycXHR9u3bbdrLli1L0AEAACVSkcKOq6urKlasyL10AADATaPIV2O99NJLGjlypI4fP14c9QAAANhVkefsTJ8+XX/88YdCQkIUFhYmLy8vm+WbN2+2W3EAAADXq8hhp3379sVQBgAAQPEoctgZPXp0cdQBAABQLIo8ZwcAAOBmUuQjO05OTle8zJwrtQAAQElS5LCzePFim/c5OTn69ddfNXfuXL366qt2KwwAAMAeihx2Hn744XxtnTp1Us2aNbVw4UI98cQTdikMAADAHuw2Z6dRo0ZasWKFvVYHAABgF3YJO+fOndPUqVN122232WN1AAAAdlPk01j/fuCnYRg6deqUSpUqpU8++cSuxQEAAFyvIoedd955xybsODk5qXz58mrYsKHKlClj1+IAAACuV5HDTu/evYuhDAAAgOJR5Dk78fHx+vzzz/O1f/7555o7d65digIAALCXIoedCRMmqFy5cvnaAwICNH78eLsUBQAAYC9FDjsHDhxQREREvvawsDAdOHDALkUBAADYS5HDTkBAgLZu3ZqvfcuWLfL397dLUQAAAPZS5LDTvXt3DRgwQKtWrVJubq5yc3O1cuVKDRw4UN26dSuOGgEAAK5Zka/Geu2117Rv3z7de++9cnG5+PG8vDz17NmTOTsAAKDEKXLYcXNz08KFC/X6668rOTlZnp6eioqKUlhYWHHUBwAAcF2KHHYuiYyMVGRkpD1rAQAAsLsiz9np2LGjJk6cmK990qRJ6ty5s12KAgAAsJcih521a9fqwQcfzNf+wAMPaO3atXYpCgAAwF6KHHZOnz4tNze3fO2urq7KzMy0S1EAAAD2UuSwExUVpYULF+ZrX7BggWrUqGGXogAAAOylyBOUR40apQ4dOmjPnj1q1aqVJGnFihWaP3++vvjiC7sXCAAAcD2KHHbatWunJUuWaPz48friiy/k6emp2rVra+XKlSpbtmxx1AgAAHDNrunS85iYGMXExEiSMjMz9emnn+qFF17Qpk2blJuba9cCAQAArkeR5+xcsnbtWvXq1UshISF666231KpVK/3yyy/2rA0AAOC6FenITlpamhISEjRnzhxlZmaqS5cuysrK0pIlS5icDAAASqRCH9lp166dqlatqq1bt2rKlCk6fPiwpk2bVpy1AQAAXLdCH9n59ttvNWDAAPXv35/HRAAAgJtGoY/s/Pjjjzp16pTq1aunhg0bavr06Tp27Fhx1gYAAHDdCh12GjVqpA8++EB//fWXnn76aS1YsEAhISHKy8tTYmKiTp06VZx1AgAAXJMiX43l5eWlvn376scff9S2bdv0/PPP64033lBAQIAeeuih4qgRAADgml3zpeeSVLVqVU2aNEmHDh3Sp59+aq+aAAAA7Oa6ws4lzs7Oat++vZYuXWqP1V3WG2+8IYvFokGDBlnbzp8/r9jYWPn7+8vb21sdO3ZUenp6sdYBAABuHnYJOzfChg0b9P777+uOO+6waR88eLC+/vprff7551qzZo0OHz6sDh06OKhKAABQ0twUYef06dPq0aOHPvjgA5UpU8bafvLkSc2ZM0dvv/22WrVqpXr16ik+Pl4///wzd3MGAACSbpKwExsbq5iYGLVu3dqmfdOmTcrJybFpr1atmipWrKh169Zddn1ZWVnKzMy0eQEAAHO6pgeB3kgLFizQ5s2btWHDhnzL0tLS5ObmptKlS9u0BwYGKi0t7bLrnDBhgl599VV7lwoAAEqgEn1k5+DBgxo4cKDmzZsnDw8Pu613xIgROnnypPV18OBBu60bAACULCU67GzatElHjhxR3bp15eLiIhcXF61Zs0ZTp06Vi4uLAgMDlZ2drYyMDJvPpaenKygo6LLrdXd3l6+vr80LAACYU4k+jXXvvfdq27ZtNm19+vRRtWrVNGzYMIWGhsrV1VUrVqxQx44dJUkpKSk6cOCAGjdu7IiSAQBACVOiw46Pj49q1apl0+bl5SV/f39r+xNPPKEhQ4aobNmy8vX11XPPPafGjRurUaNGjigZAACUMCU67BTGO++8IycnJ3Xs2FFZWVmKjo7We++95+iyAABACXHThZ3Vq1fbvPfw8NCMGTM0Y8YMxxQEAABKtBI9QRkAAOB6EXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpEXYAAICpleiwM2HCBDVo0EA+Pj4KCAhQ+/btlZKSYtPn/Pnzio2Nlb+/v7y9vdWxY0elp6c7qGIAAFDSlOiws2bNGsXGxuqXX35RYmKicnJydN999+nMmTPWPoMHD9bXX3+tzz//XGvWrNHhw4fVoUMHB1YNAABKEhdHF3Aly5cvt3mfkJCggIAAbdq0SXfffbdOnjypOXPmaP78+WrVqpUkKT4+XtWrV9cvv/yiRo0aOaJsAABQgpToIzv/dvLkSUlS2bJlJUmbNm1STk6OWrdube1TrVo1VaxYUevWrbvserKyspSZmWnzAgAA5nTThJ28vDwNGjRITZs2Va1atSRJaWlpcnNzU+nSpW36BgYGKi0t7bLrmjBhgvz8/Kyv0NDQ4iwdAAA40E0TdmJjY7V9+3YtWLDgutc1YsQInTx50vo6ePCgHSoEAAAlUYmes3NJXFycli1bprVr16pChQrW9qCgIGVnZysjI8Pm6E56erqCgoIuuz53d3e5u7sXZ8kAAKCEKNFHdgzDUFxcnBYvXqyVK1cqIiLCZnm9evXk6uqqFStWWNtSUlJ04MABNW7c+EaXCwAASqASfWQnNjZW8+fP11dffSUfHx/rPBw/Pz95enrKz89PTzzxhIYMGaKyZcvK19dXzz33nBo3bsyVWAAAQFIJDzszZ86UJN1zzz027fHx8erdu7ck6Z133pGTk5M6duyorKwsRUdH67333rvBlQIAgJKqRIcdwzCu2sfDw0MzZszQjBkzbkBFAADgZlOi5+wAAABcL8IOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNcIOAAAwNdOEnRkzZig8PFweHh5q2LCh1q9f7+iSAABACWCKsLNw4UINGTJEo0eP1ubNm1W7dm1FR0fryJEjji4NAAA4mCnCzttvv62nnnpKffr0UY0aNTRr1iyVKlVKH374oaNLAwAADnbTh53s7Gxt2rRJrVu3trY5OTmpdevWWrdunQMrAwAAJYGLowu4XseOHVNubq4CAwNt2gMDA/Xbb78V+JmsrCxlZWVZ3588eVKSlJmZaff68rLOFrpvpsUo/IoLUWuxbLuQ+6iw274pxuzIbbO/b+y22d83dtvs7xu77RK+v6/FpX+3DeMqtRg3uT///NOQZPz888827UOHDjXuuuuuAj8zevRoQxIvXrx48eLFywSvgwcPXjEr3PRHdsqVKydnZ2elp6fbtKenpysoKKjAz4wYMUJDhgyxvs/Ly9Px48fl7+8vi8VSrPVeTmZmpkJDQ3Xw4EH5+vo6pIYb7VYcs3Rrjpsx3xpjlm7NcTNmx43ZMAydOnVKISEhV+x304cdNzc31atXTytWrFD79u0lXQwvK1asUFxcXIGfcXd3l7u7u01b6dKli7nSwvH19b1l/me55FYcs3Rrjpsx3zpuxXEzZsfw8/O7ap+bPuxI0pAhQ9SrVy/Vr19fd911l6ZMmaIzZ86oT58+ji4NAAA4mCnCTteuXXX06FG98sorSktL05133qnly5fnm7QMAABuPaYIO5IUFxd32dNWNwN3d3eNHj063+k1M7sVxyzdmuNmzLeOW3HcjLnksxjG1a7XAgAAuHnd9DcVBAAAuBLCDgAAMDXCDgAAMDXCDgAAMDXCTgkwY8YMhYeHy8PDQw0bNtT69esdXVKxmjBhgho0aCAfHx8FBASoffv2SklJcXRZN9Qbb7whi8WiQYMGObqUYvfnn3/qsccek7+/vzw9PRUVFaWNGzc6uqxik5ubq1GjRikiIkKenp6qXLmyXnvttas/u+cmsnbtWrVr104hISGyWCxasmSJzXLDMPTKK68oODhYnp6eat26tXbv3u2YYu3oSuPOycnRsGHDFBUVJS8vL4WEhKhnz546fPiw4wq2g6v9rP/pmWeekcVi0ZQpU25YfYVF2HGwhQsXasiQIRo9erQ2b96s2rVrKzo6WkeOHHF0acVmzZo1io2N1S+//KLExETl5OTovvvu05kzZxxd2g2xYcMGvf/++7rjjjscXUqxO3HihJo2bSpXV1d9++232rlzp9566y2VKVPG0aUVm4kTJ2rmzJmaPn26du3apYkTJ2rSpEmaNm2ao0uzmzNnzqh27dqaMWNGgcsnTZqkqVOnatasWUpKSpKXl5eio6N1/vz5G1ypfV1p3GfPntXmzZs1atQobd68WYsWLVJKSooeeughB1RqP1f7WV+yePFi/fLLL1d9bIPD2ONhnLh2d911lxEbG2t9n5uba4SEhBgTJkxwYFU31pEjRwxJxpo1axxdSrE7deqUERkZaSQmJhotWrQwBg4c6OiSitWwYcOMZs2aObqMGyomJsbo27evTVuHDh2MHj16OKii4iXJWLx4sfV9Xl6eERQUZLz55pvWtoyMDMPd3d349NNPHVBh8fj3uAuyfv16Q5Kxf//+G1NUMbvcmA8dOmTcdtttxvbt242wsDDjnXfeueG1XQ1HdhwoOztbmzZtUuvWra1tTk5Oat26tdatW+fAym6skydPSpLKli3r4EqKX2xsrGJiYmx+5ma2dOlS1a9fX507d1ZAQIDq1KmjDz74wNFlFasmTZpoxYoV+v333yVJW7Zs0Y8//qgHHnjAwZXdGKmpqUpLS7P5jvv5+alhw4a31O816eLvNovF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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import torch\n",
    "import os\n",
    "import numpy as np\n",
    "\n",
    "max_rtids_path = \"pretrained/max_RTIDS_pretrained.pt\"\n",
    "max_encon_path = \"pretrained/max_pretrained_enc.pt\"\n",
    "batch_size = 128\n",
    "dropout_rate = 0.5\n",
    "d_model = 32\n",
    "heads = 8\n",
    "N = 6\n",
    "trg_vocab = 2\n",
    "\n",
    "def accuracy_per_class(model, loader):\n",
    "    model.eval()\n",
    "    model.to(\"cuda\")\n",
    "    correct = np.zeros(15, dtype=np.int64)\n",
    "    wrong = np.zeros(15, dtype=np.int64)\n",
    "    with torch.no_grad():\n",
    "        for src, trg, at_class in loader:\n",
    "            src, trg = src.to(\"cuda\"), trg.to(\"cuda\")\n",
    "            output = model(src)            \n",
    "            for label, pred, at_c in zip(trg, output, at_class.cpu().numpy()):\n",
    "                at_c = int(at_c)\n",
    "                if torch.eq(torch.argmax(pred),torch.argmax(label)):\n",
    "                    correct[at_c] += 1\n",
    "                else:\n",
    "                    wrong[at_c] += 1\n",
    "    accuracy = 100. * correct / (correct + wrong)\n",
    "    return accuracy\n",
    "\n",
    "_, val_data = load_data()\n",
    "val_loader = get_data_loader(val_data, 128)\n",
    "\n",
    "x_values = np.arange(15)\n",
    "\n",
    "if os.path.exists(max_rtids_path):\n",
    "    rtids_model = RTIDS_Transformer(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "    state = torch.load(max_rtids_path)\n",
    "    rtids_model.load_state_dict(state[\"model_state_dict\"])\n",
    "    rtids_acc = accuracy_per_class(rtids_model, val_loader)\n",
    "else:\n",
    "    rtids_acc = [0 for _ in range(15)]\n",
    "    \n",
    "if os.path.exists(max_encon_path):\n",
    "    encon_model = IDS_Encoder_Only(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "    state = torch.load(max_encon_path)\n",
    "    encon_model.load_state_dict(state[\"model_state_dict\"])\n",
    "    encon_acc = accuracy_per_class(encon_model, val_loader) \n",
    "else:\n",
    "    encon_acc = [0 for _ in range(15)]\n",
    "    \n",
    "plt.figure(1)\n",
    "width = 0.35\n",
    "plt.bar(x_values - width/2, rtids_acc, width, label='RTIDS')\n",
    "plt.bar(x_values + width/2, encon_acc, width, label='Encoder Only')\n",
    "\n",
    "plt.xlabel('Attack Class')\n",
    "if label_mapping != {}:\n",
    "    plt.xticks(x_values, [label_mapping[val] for val in x_values])\n",
    "plt.ylabel('Accuracy')\n",
    "plt.title('Accuracy per Class Comparison')\n",
    "plt.ylim(0, 100)\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "eeaa820b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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0//wyGzmzAdVvXp1hYaGau7cuVq9enWG5ampqXr//fezXD+z1+jatWtasGCBWb8rV65k+J26NyvivfP+z38bbWxsVK5cObM+AHIGI04AHkqJEiW0ZMkStW3bVmXLllWnTp30wgsvKDU1VT///LNp2uysNGvWTCNHjlTXrl310ksv6eDBg/ryyy/N/sdaujtZgZeXl2rUqCFPT0/FxsZq2rRpatq0qVxcXHT16lUVLlxYr776qsqXLy9nZ2dt3rxZu3btMhv9eRxTpkzRyy+/rIoVK+rNN99UsWLFlJCQoHXr1ikmJsZ0PF988YXc3NwUEBCgHTt2aPPmzcqfP7/ZtoKDg2Vra6tx48bp2rVrsre3N32nyz+9+eabmj17trp06aI9e/bIz89PK1euVHR0tCZPnvxYN6hb0qJFC7Vo0eK+fUqUKKFRo0Zp0KBBSkhIUMuWLeXi4qL4+Hh98803evPNN01/RFaqVEnLli1T3759VaVKFTk7O6t58+YPVZONjY1mzpyp5s2bKzg4WF27dpW3t7eOHj2qw4cPa+PGjTp+/Ljq16+vsLAwBQQEKFeuXPrmm290/vx5vf766/fd/ksvvaTp06erV69eKlOmjDp27Ch/f3/9+eefioqK0po1azRq1ChJd0ce6tatqyFDhighIUHly5fX999/r//973/q06ePaXQsu/j4+GjcuHFKSEhQqVKltGzZMsXExOizzz4zTfXdrFkzrVq1Sq1atVLTpk0VHx+vWbNmKSAgINMg+CAe5Hx6eHho0KBBGjFihEJDQ/XKK6/o2LFjmjFjhqpUqWI2EUR2eOGFFxQSEmI2Hbl093u47vn444+1detWvfjii+rRo4cCAgJ0+fJl7d27V5s3b9bly5cfef+ff/65GjVqpNatW6t58+aqX7++nJycdOLECS1dulTnzp3L8rucGjVqZBoleuutt5ScnKw5c+aoYMGCOnfunKnfokWLNGPGDLVq1UolSpTQn3/+qTlz5sjV1VVNmjSRJHXv3l2XL19WvXr1VLhwYZ06dUpTp05VcHBwll9xACCbPNE5/AD8axw/ftzYo0cPo5+fn9HOzs7o4uJirFGjhnHq1KnGW7dumfplNh15v379jN7e3kZHR0djjRo1jDt27MgwJffs2bONtWrVMubPn99ob29vLFGihLF///7Ga9euGY3Gu1MZ9+/f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05F/8skn6tGjh7p27SpJmjVrltatW6f58+dr4MCBGfr//PPPqlGjhtq3v/tt4H5+fmrXrp1+/fXXJ1o3AACAtU1/+4cnur/wWfWe6P6swWg06q233tLKlSt15coV7du3T8HBwdYuC08Jq404paamas+ePWrQoMH/FWNjowYNGmjHjh2ZrvPSSy9pz549psv5fvvtN61fv15NmjTJcj8pKSm6fv262QMAAAA5q0uXLjIYDDIYDMqdO7eKFSumDz74QLdu3dLChQtNy7J6JCQkKDIy0iy4REZGmpbnypVLBQoUUK1atTR58mSlpKSY7T8+Pl7t27eXj4+PHBwcVLhwYbVo0UJHjx7NsuYNGzZo4cKFWrt2rc6dO6cXXnhB27dvV/PmzeXj4yODwaDVq1fn0BnD085qI06XLl1SWlqaPD09zdo9PT2zfEO3b99ely5d0ssvvyyj0ag7d+7o7bffvu+lemPHjtWIESOytXYAAABYFhoaqgULFuj27dvas2ePOnfuLIPBoMjISIWGhpr6tW7dWi+88IJGjhxpavPw8Mh0m4GBgdq8ebPS09P1xx9/KCoqSqNGjdIXX3yhqKgoubi46Pbt22rYsKFKly6tVatWydvbW2fOnNF3332nq1evZllvXFycvL299dJLL5nabty4ofLly6tbt25q3br145+UHJCamio7Oztrl/GvZ/XJIR5GVFSUxowZoxkzZmjv3r1atWqV1q1bp48++ijLdQYNGqRr166ZHqdPn36CFQMAADy/7O3t5eXlJV9fX7Vs2VINGjTQpk2b5OjoKC8vL9PDzs5OefLkMWuztbXNdJu5cuWSl5eXfHx8FBQUpHfeeUfbtm3ToUOHNG7cOEnS4cOHFRcXpxkzZqhatWoqWrSoatSooVGjRqlatWqZbrdLly565513lJiYKIPBID8/P0lS48aNNWrUKLVq1eqBj9toNCoyMlJFihSRvb29fHx81Lt3b9PylJQUDRgwQL6+vrK3t1fJkiU1b9480/Jt27apatWqsre3l7e3twYOHKg7d+6YltepU0cRERHq06ePChQooJCQEEnSoUOH1LhxYzk7O8vT01MdO3bUpUuXHrhu3J/VglOBAgVka2ur8+fPm7WfP39eXl5ema4zbNgwdezYUd27d1dQUJBatWqlMWPGaOzYsUpPT890HXt7e7m6upo9AAAA8GQdOnRIP//8c46MjJQpU0aNGzfWqlWrJN0drbKxsdHKlSuVlpb2QNv49NNPNXLkSBUuXFjnzp3Trl27Hrmer7/+WpMmTdLs2bN14sQJrV69WkFBQablnTp10ldffaUpU6YoNjZWs2fPlrOzsyTp999/V5MmTVSlShXt379fM2fO1Lx58zRq1CizfSxatEh2dnaKjo7WrFmzdPXqVdWrV08VKlTQ7t27tWHDBp0/f15hYWGPfBwwZ7VL9ezs7FSpUiVt2bJFLVu2lCSlp6dry5YtioiIyHSdv/76SzY25lnv3v9GGI3GHK0XAAAAD2ft2rVydnbWnTt3lJKSIhsbG02bNi1H9lWmTBl9//33kqRChQppypQp+uCDDzRixAhVrlxZdevWVYcOHVS8ePFM13dzc5OLi4tsbW2z/E/8B5WYmCgvLy81aNBAuXPnVpEiRVS1alVJ0vHjx7V8+XJt2rTJdK//32uaMWOGfH19NW3aNBkMBpUpU0Znz57VgAED9OGHH5r+Fvb399f48eNN640aNUoVKlTQmDFjTG3z58+Xr6+vjh8/rlKlSj3WMcHKl+r17dtXc+bM0aJFixQbG6uePXvqxo0bpln2OnXqpEGDBpn6N2/eXDNnztTSpUsVHx+vTZs2adiwYWrevHmWw7kAAACwjrp16yomJka//vqrOnfurK5du6pNmzY5si+j0SiDwWB6Hh4erqSkJH355ZeqXr26VqxYocDAQG3atClb9ztmzBg5OzubHomJiXrttdd08+ZNFS9eXD169NA333xjutQuJiZGtra2ql27dqbbi42NVfXq1c2OpUaNGkpOTtaZM2dMbZUqVTJbb//+/dq6datZLWXKlJF0994tPD6rTkfetm1bXbx4UR9++KGSkpIUHBysDRs2mCaMSExMNBthGjp0qAwGg4YOHarff/9dHh4eat68uUaPHm2tQwAAAEAWnJycVLJkSUl3Rz/Kly+vefPm6Y033sj2fcXGxqpYsWJmbS4uLmrevLmaN2+uUaNGKSQkRKNGjVLDhg2zbb9vv/222eVwPj4+ypUrl44dO6bNmzdr06ZN6tWrl/773/9q27ZtcnR0zJb9Ojk5mT1PTk5W8+bNTfd5/Z23t3e27PN5Z9XgJEkRERFZXpoXFRVl9jxXrlwaPny4hg8f/gQqAwAAQHaxsbHR4MGD1bdvX7Vv3z7bAoQkHT16VBs2bDC7Uumf7l329vPPP2fbfiUpX758ypcvX4Z2R0dHU2gLDw9XmTJldPDgQQUFBSk9PV3btm0z+1qee8qWLauvv/7abAQtOjpaLi4uKly4cJZ1VKxYUV9//bX8/PyUK5fV/8T/V3qmZtUDAADAs+u1116Tra2tpk+f/sjbuHPnjpKSknT27FkdPHhQU6dOVe3atRUcHKz+/ftLuns5XIsWLbRy5UodOXJEJ0+e1Lx58zR//ny1aNHiofaXnJysmJgYxcTESLr7/VAxMTFKTEzMcp2FCxdq3rx5OnTokH777TctXrxYjo6OKlq0qPz8/NS5c2d169ZNq1evVnx8vKKiorR8+XJJUq9evXT69Gm98847Onr0qP73v/9p+PDh6tu3b4Z7/f8uPDxcly9fVrt27bRr1y7FxcVp48aN6tq16wNPkIH7I44CAAA8g8Jn1bN2CQ8tV65cioiI0Pjx49WzZ88Ml5s9iMOHD8vb21u2trZyc3NTQECABg0apJ49e8re3l6SVLhwYfn5+WnEiBFKSEgwTS8+YsQIvffeew+1v927d6tu3bqm53379pUkde7cWQsXLsx0HXd3d3388cfq27ev0tLSFBQUpG+//Vb58+eXJM2cOVODBw9Wr1699Mcff6hIkSKm7yUtVKiQ1q9fr/79+6t8+fLKly+f3njjDQ0dOvS+dfr4+Cg6OloDBgxQo0aNlJKSoqJFiyo0NPS+gQsPzmB8zqaju379utzc3HTt2rWnZmpyv4HrrF1CphIc2lu7hKxFXsvWzQUtCrLcyUqWj71juZOVlD0am23bmv72D9m2rex268on1i4hS/2WrbV2CXiOPa2fX9K/5zPs1q1bio+PV7FixeTg4JCDReFRXTh13dolZKlg0afjb11ru9/v0cNkA+InAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYkMvaBQAAAODhTWzb7Inur9+ytU90fzklISFBxYoV0759+xQcHGztcu7L089NC2Z/qSYhj/5af/bZZ/roo4/0+++/65NPPlGfPn2yr8DnDCNOAAAAyHZdunSRwWDI8AgNDbV2aTnqytXLGjpioCrVeEGF/QuoXNXSerd/uM78fvqJ13L9+nVFRERowIAB+v333/Xmm2/q3Llzat++vUqVKiUbGxuC1EMgOAEAACBHhIaG6ty5c2aPr776ytplPbbU1NRM269cvawmrRpoe3SUxo+apF+i9mn21PlKOPWbQlrUVUJi/BOtMzExUbdv31bTpk3l7e2tPHnyKCUlRR4eHho6dKjKly//ROt5UFmdX2sjOAEAACBH2Nvby8vLy+yRN29e03KDwaC5c+eqVatWypMnj/z9/bVmzRqzbRw+fFjNmjWTq6urXFxcVLNmTcXFxUmS0tPTNXLkSBUuXFj29vYKDg7Whg0bzNbfuXOnKlSoIAcHB1WuXFn79u3LUOehQ4fUuHFjOTs7y9PTUx07dtSlS5dMy+vUqaOIiAj16dNHBQoUUEhISKbHO/a/HynpfJJWLv6f6tdtqMKFfFX9xRpa+vkq5c6VW4OGvW/q26ptUw2O/EAjxw5T6fJF9UJlf/130tgsz2Xrds006MP3zdou/XFJhf0LaHt0VIb+S1d8qaCgIElS8eLFZTAYlJCQID8/P3366afq1KmT3NzcstzfP61cuVJBQUFydHRU/vz51aBBA924ccO0fP78+QoMDJS9vb28vb0VERFhWpaYmKgWLVrI2dlZrq6uCgsL0/nz503LIyMjFRwcrLlz56pYsWJycHCQJF29elXdu3eXh4eHXF1dVa9ePe3fv/+Ba85uBCcAAABYzYgRIxQWFqYDBw6oSZMm6tChgy5fvixJ+v3331WrVi3Z29vrhx9+0J49e9StWzfduXNHkvTpp59q4sSJmjBhgg4cOKCQkBC98sorOnHihCQpOTlZzZo1U0BAgPbs2aPIyEi9/755+Lh69arq1aunChUqaPfu3dqwYYPOnz+vsLAws36LFi2SnZ2doqOjNWvWrAzHkZ6ertXffq02LV5TwYKeZsscHRzVpeMb2rp9i65cvWxqX/71V8rj6KTvVv+gDweN1MQp47Ttxx8yPU8dXu+sVf9boZSUFFPbym+WycvTWzVfqp2hf4vmrbV582ZJd8PjuXPn5Ovrm/mLYMG5c+fUrl07devWTbGxsYqKilLr1q1lNBolSTNnzlR4eLjefPNNHTx4UGvWrFHJkiVN56VFixa6fPmytm3bpk2bNum3335T27ZtzfZx8uRJff3111q1apViYmIkSa+99pouXLig7777Tnv27FHFihVVv3590/vjSWNyCAAAAOSItWvXytnZ2axt8ODBGjx4sOl5ly5d1K5dO0nSmDFjNGXKFO3cuVOhoaGaPn263NzctHTpUuXOnVuSVKpUKdO6EyZM0IABA/T6669LksaNG6etW7dq8uTJmj59upYsWaL09HTNmzdPDg4OCgwM1JkzZ9SzZ0/TNqZNm6YKFSpozJgxprb58+fL19dXx48fN+3P399f48ePz/JYL/1xSdeuX5N/ydKZLi9VorSMRqPiE+KVNzifJCmgTKDe7zNQklS8WAnN+/wzbY/epto162VYv2lIcw3+8H1t2LROLZq1liQtW7lEr7/aQQaDIUN/R4e7I0OS5OHhIS8vryxrt+TcuXO6c+eOWrduraJFi0qSaTRLkkaNGqV+/frp3XffNbVVqVJFkrRlyxYdPHhQ8fHxpuD2+eefKzAwULt27TL1S01N1eeffy4PDw9J0k8//aSdO3fqwoULsre3l3T39V69erVWrlypN99885GP51Ex4gQAAIAcUbduXcXExJg93n77bbM+5cqVM/3s5OQkV1dXXbhwQZIUExOjmjVrmkLT312/fl1nz55VjRo1zNpr1Kih2NhYSVJsbKzKlStnuvRLkqpXr27Wf//+/dq6daucnZ1NjzJlykiS6ZJASapUqdIDHfO9UZgHEVAm0Oy5p4eXLv1xKdO+Dg4OerXV6/pq+WJJ0oFDMTp6/Ijavtr+gff3IH788Uezc/Hll1+qfPnyql+/voKCgvTaa69pzpw5unLliiTpwoULOnv2rOrXr5/p9mJjY+Xr62s22hUQECB3d3fT6yRJRYsWNYUm6e7rkpycrPz585vVEx8fb/a6PEmMOAEAACBHODk5mS7Zyso/Q5HBYFB6erokydHRMcdquyc5OVnNmzfXuHHjMizz9vY2/ezk5HTf7RTIX0Burm46EXcs0+XH447JYDComF8xU1uuXBmP3fj/jz0zHV7vpPpNXtbZc7/rqxVf6uWXasm3cJEs+186fUqSdPFUvBzSbmdYnnrzpm5cu6qkuBOmtsL53LXpf6tNzz0K5NfFhN/0xawZ2rV3r7b9+JMmTZyoQQMHav3XK5Tv/9+zdvn3M2bbuef6pYtKu3Mn02V/98/zm5ycLG9vb0VFRWXo6+7uft9t5RRGnAAAAPBUKleunH788Ufdvp3xj35XV1f5+PgoOjrarD06OloBAQGSpLJly+rAgQO6deuWafkvv/xi1r9ixYo6fPiw/Pz8VLJkSbOHpbD0dzY2NnqlaSut+t9KXbhw3mzZzVs3tfCLeapbq77yuud74G3+U0CZQJUPqqDFXy3SN/9boXavdXzkbWXF0cFBxfyKmh73LrU0GAyqWqmS+vd5V5vWrJZd7txa//0mOTs7y7dwYf24Y0em2/MvUUJnz53T72fPmdqOnTipq1evml6nzFSsWFFJSUnKlStXhtelQIEC2XvQD4jgBAAAgByRkpKipKQks8ffZ6uzJCIiQtevX9frr7+u3bt368SJE/riiy907NjdUZ3+/ftr3LhxWrZsmY4dO6aBAwcqJibGdK9N+/btZTAY1KNHDx05ckTr16/XhAkTzPYRHh6uy5cvq127dtq1a5fi4uK0ceNGde3aVWlpaQ91vIM/GK6CHgX1WseW2rJ1k34/e0Y7fo3W651a6/ad2xr70QTLG7Ggw+udNHXWJBmNxkf+YtxDR47o0JEjuvHXX/rj8mUdOnJEx06czLL/3pj9+nTGTMUcPKgzZ89q/cbv9cfly/IvWUKS9H7vCM2eN19zF32u3xISdODQYc37/HNJUq0aL6lsqVIK79dPBw4d1r79+9W7/weqXbu2KleunOU+GzRooOrVq6tly5b6/vvvlZCQoJ9//llDhgzR7t27H+m4HxeX6gEAADyD+i1ba+0SLNqwYYPZ5W6SVLp0aR09evSB1s+fP79++OEH9e/fX7Vr15atra2Cg4NN9zX17t1b165dU79+/XThwgUFBARozZo18vf3lyQ5Ozvr22+/1dtvv60KFSooICBA48aNU5s2bUz7uDdqNWDAADVq1EgpKSkqWrSoQkNDZWPzcGMM+fLm0/pvtmjilHHqP6SPLlw8L3e3vKpfp6GmT/pMhQs92qx2f9f6lVc1bOQgtXrlVbN7tx5Gw1damn4+cOiQvlnzrQoXKqRd27Zm2t/Z2Um/7NqtOQsXKTk5WYULFdLwQQNVv/bd2fzCWrfWrZRUfbZggUZ+PE758uZVs9C7U7YbDAYtmD1TQ0d8pFbtO8jGYFDdWrU0Z8GC+9ZoMBi0fv16DRkyRF27dtXFixfl5eWlWrVqydPT877r5hSD8WHuYPsXuH79utzc3HTt2jW5urpauxxJkt/AddYuIVMJDtl7s2G2iryWrZsLWhRkuZOVLB97x9olZKns0VjLnR7Q9Lczn371aXDryifWLiFLz8IfTvj3elo/v6R/z2fYrVu3FB8fb/bdNni6XDh1/YnuL/H0Kb1YO1gb12xVuReC79s3/c75+y63Jq8S/k9sX/f7PXqYbMCIEwAAAPCUu337tq5cuayPJ45SpQpVLIYmZD/ucQIAAACecjt3/6KgqqUUc2Cvxo+eZO1ynkuMOAEAAABPuRrVa+p8QvbeqoCHw4gTAAAAAFhAcAIAAHjKpd/nS1EB3F92zYXHpXoAAABPKTs7O9nY2Ojs2bPy8PCQnZ2dDAaDtcvC39y+k2rtErKU/pDfQ/Uk/f1LiXOS0WjUxYsXZTAYlDt37sfaFsEJAADgKWVjY6NixYrp3LlzOnv2rLXLQSb+/OPJBIBHYUx/slOlP4zktCf3jUgGg0GFCxeWra3tY22H4AQAAPAUs7OzU5EiRXTnzh2lPcUjCM+rLxf+Yu0SspR6faG1S8hS10mznti+cufO/dihSSI4AQAAPPXuXWb0uJcaIfvduvb03n9268ola5eQpWfxC52ZHAIAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALclm7AAAAADyaoEVB1i4hSwc7H7R2CUC2YsQJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAW5LJ2AQAAAPj3iS1T1tolZKns0Vhrl4BnECNOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABggdWD0/Tp0+Xn5ycHBwe9+OKL2rlz5337X716VeHh4fL29pa9vb1KlSql9evXP6FqAQAAADyPcllz58uWLVPfvn01a9Ysvfjii5o8ebJCQkJ07NgxFSxYMEP/1NRUNWzYUAULFtTKlStVqFAhnTp1Su7u7k++eAAAAADPDasGp08++UQ9evRQ165dJUmzZs3SunXrNH/+fA0cODBD//nz5+vy5cv6+eeflTt3bkmSn5/fkywZAAAAwHPIapfqpaamas+ePWrQoMH/FWNjowYNGmjHjh2ZrrNmzRpVr15d4eHh8vT01AsvvKAxY8YoLS0ty/2kpKTo+vXrZg8AAAAAeBhWC06XLl1SWlqaPD09zdo9PT2VlJSU6Tq//fabVq5cqbS0NK1fv17Dhg3TxIkTNWrUqCz3M3bsWLm5uZkevr6+2XocAAAAAP79rD45xMNIT09XwYIF9dlnn6lSpUpq27athgwZolmzZmW5zqBBg3Tt2jXT4/Tp00+wYgAAAAD/Bla7x6lAgQKytbXV+fPnzdrPnz8vLy+vTNfx9vZW7ty5ZWtra2orW7askpKSlJqaKjs7uwzr2Nvby97ePnuLBwAAAPBcsdqIk52dnSpVqqQtW7aY2tLT07VlyxZVr14903Vq1KihkydPKj093dR2/PhxeXt7ZxqaAAAAACA7WPVSvb59+2rOnDlatGiRYmNj1bNnT924ccM0y16nTp00aNAgU/+ePXvq8uXLevfdd3X8+HGtW7dOY8aMUXh4uLUOAQAAAMBzwKrTkbdt21YXL17Uhx9+qKSkJAUHB2vDhg2mCSMSExNlY/N/2c7X11cbN27Ue++9p3LlyqlQoUJ69913NWDAAGsdAgAAAIDngFWDkyRFREQoIiIi02VRUVEZ2qpXr65ffvklh6sCAAAAgP/zTM2qBwAAAADWQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwIFuC0/Xr17V69WrFxsZmx+YAAAAA4KnySMEpLCxM06ZNkyTdvHlTlStXVlhYmMqVK6evv/46WwsEAAAAAGt7pOC0fft21axZU5L0zTffyGg06urVq5oyZYpGjRqVrQUCAAAAgLU9UnC6du2a8uXLJ0nasGGD2rRpozx58qhp06Y6ceJEthYIAAAAANb2SMHJ19dXO3bs0I0bN7RhwwY1atRIknTlyhU5ODhka4EAAAAAYG25HmWlPn36qEOHDnJ2dlaRIkVUp04dSXcv4QsKCsrO+gAAAADA6h4pOPXq1UtVq1bV6dOn1bBhQ9nY3B24Kl68OPc4AQAAAPjXeaTgJEmVK1dWuXLlFB8frxIlSihXrlxq2rRpdtYGAAAAAE+FR7rH6a+//tIbb7yhPHnyKDAwUImJiZKkd955Rx9//HG2FggAAAAA1vZIwWnQoEHav3+/oqKizCaDaNCggZYtW5ZtxQEAAADA0+CRLtVbvXq1li1bpmrVqslgMJjaAwMDFRcXl23FAQAAAMDT4JFGnC5evKiCBQtmaL9x44ZZkAIAAACAf4NHCk6VK1fWunXrTM/vhaW5c+eqevXq2VMZAAAAADwlHulSvTFjxqhx48Y6cuSI7ty5o08//VRHjhzRzz//rG3btmV3jQAAAABgVY804vTyyy9r//79unPnjoKCgvT999+rYMGC2rFjhypVqpTdNQIAAACAVT30iNPt27f11ltvadiwYZozZ05O1AQAAAAAT5WHHnHKnTu3vv7665yoBQAAAACeSo90qV7Lli21evXqbC4FAAAAAJ5OjzQ5hL+/v0aOHKno6GhVqlRJTk5OZst79+6dLcUBAAAAwNPgkYLTvHnz5O7urj179mjPnj1mywwGA8EJAAAAwL/KIwWn+Pj47K4DAAAAAJ5aj3SP098ZjUYZjcbsqAUAAAAAnkqPHJw+//xzBQUFydHRUY6OjipXrpy++OKL7KwNAAAAAJ4Kj3Sp3ieffKJhw4YpIiJCNWrUkCT99NNPevvtt3Xp0iW999572VokAAAAAFjTIwWnqVOnaubMmerUqZOp7ZVXXlFgYKAiIyMJTgAAAAD+VR7pUr1z587ppZdeytD+0ksv6dy5c49dFAAAAAA8TR4pOJUsWVLLly/P0L5s2TL5+/s/dlEAAAAA8DR5pEv1RowYobZt22r79u2me5yio6O1ZcuWTAMVAAAAADzLHmnEqU2bNvr1119VoEABrV69WqtXr1aBAgW0c+dOtWrVKrtrBAAAAACreqQRJ0mqVKmSFi9enJ21AAAAAMBT6ZFGnNavX6+NGzdmaN+4caO+++67xy4KAAAAAJ4mjxScBg4cqLS0tAztRqNRAwcOfOyiAAAAAOBp8kjB6cSJEwoICMjQXqZMGZ08efKxiwIAAACAp8kjBSc3Nzf99ttvGdpPnjwpJyenxy4KAAAAAJ4mjxScWrRooT59+iguLs7UdvLkSfXr10+vvPJKthUHAAAAAE+DRwpO48ePl5OTk8qUKaNixYqpWLFiKlOmjPLnz68JEyZkd40AAAAAYFWPNB25m5ubfv75Z23atEn79++Xo6Ojypcvr5o1a2Z3fQAAAABgdQ814rRjxw6tXbtWkmQwGNSoUSMVLFhQEyZMUJs2bfTmm28qJSUlRwoFAAAAAGt5qOA0cuRIHT582PT84MGD6tGjhxo2bKiBAwfq22+/1dixY7O9SAAAAACwpocKTjExMapfv77p+dKlS1W1alXNmTNHffv21ZQpU7R8+fJsLxIAAAAArOmhgtOVK1fk6elper5t2zY1btzY9LxKlSo6ffp09lUHAAAAAE+BhwpOnp6eio+PlySlpqZq7969qlatmmn5n3/+qdy5c2dvhQAAAABgZQ8VnJo0aaKBAwfqxx9/1KBBg5QnTx6zmfQOHDigEiVKZHuRAAAAAGBNDzUd+UcffaTWrVurdu3acnZ21qJFi2RnZ2daPn/+fDVq1CjbiwQAAAAAa3qo4FSgQAFt375d165dk7Ozs2xtbc2Wr1ixQs7OztlaIAAAAABY2yN/AW5m8uXL91jFAAAAAMDT6KHucQIAAACA5xHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALDgqQhO06dPl5+fnxwcHPTiiy9q586dD7Te0qVLZTAY1LJly5wtEAAAAMBzzerBadmyZerbt6+GDx+uvXv3qnz58goJCdGFCxfuu15CQoLef/991axZ8wlVCgAAAOB5ZfXg9Mknn6hHjx7q2rWrAgICNGvWLOXJk0fz58/Pcp20tDR16NBBI0aMUPHixZ9gtQAAAACeR1YNTqmpqdqzZ48aNGhgarOxsVGDBg20Y8eOLNcbOXKkChYsqDfeeMPiPlJSUnT9+nWzBwAAAAA8DKsGp0uXLiktLU2enp5m7Z6enkpKSsp0nZ9++knz5s3TnDlzHmgfY8eOlZubm+nh6+v72HUDAAAAeL5Y/VK9h/Hnn3+qY8eOmjNnjgoUKPBA6wwaNEjXrl0zPU6fPp3DVQIAAAD4t8llzZ0XKFBAtra2On/+vFn7+fPn5eXllaF/XFycEhIS1Lx5c1Nbenq6JClXrlw6duyYSpQoYbaOvb297O3tc6B6AAAAAM8Lq4442dnZqVKlStqyZYupLT09XVu2bFH16tUz9C9TpowOHjyomJgY0+OVV15R3bp1FRMTw2V4AAAAAHKEVUecJKlv377q3LmzKleurKpVq2ry5Mm6ceOGunbtKknq1KmTChUqpLFjx8rBwUEvvPCC2fru7u6SlKEdAAAAALKL1YNT27ZtdfHiRX344YdKSkpScHCwNmzYYJowIjExUTY2z9StWAAAAAD+ZawenCQpIiJCERERmS6Lioq677oLFy7M/oIAAAAA4G8YygEAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABY8FQEp+nTp8vPz08ODg568cUXtXPnziz7zpkzRzVr1lTevHmVN29eNWjQ4L79AQAAAOBxWT04LVu2TH379tXw4cO1d+9elS9fXiEhIbpw4UKm/aOiotSuXTtt3bpVO3bskK+vrxo1aqTff//9CVcOAAAA4Hlh9eD0ySefqEePHuratasCAgI0a9Ys5cmTR/Pnz8+0/5dffqlevXopODhYZcqU0dy5c5Wenq4tW7Y84coBAAAAPC+sGpxSU1O1Z88eNWjQwNRmY2OjBg0aaMeOHQ+0jb/++ku3b99Wvnz5Ml2ekpKi69evmz0AAAAA4GFYNThdunRJaWlp8vT0NGv39PRUUlLSA21jwIAB8vHxMQtffzd27Fi5ubmZHr6+vo9dNwAAAIDni9Uv1XscH3/8sZYuXapvvvlGDg4OmfYZNGiQrl27ZnqcPn36CVcJAAAA4FmXy5o7L1CggGxtbXX+/Hmz9vPnz8vLy+u+606YMEEff/yxNm/erHLlymXZz97eXvb29tlSLwAAAIDnk1VHnOzs7FSpUiWziR3uTfRQvXr1LNcbP368PvroI23YsEGVK1d+EqUCAAAAeI5ZdcRJkvr27avOnTurcuXKqlq1qiZPnqwbN26oa9eukqROnTqpUKFCGjt2rCRp3Lhx+vDDD7VkyRL5+fmZ7oVydnaWs7Oz1Y4DAAAAwL+X1YNT27ZtdfHiRX344YdKSkpScHCwNmzYYJowIjExUTY2/zcwNnPmTKWmpurVV181287w4cMVGRn5JEsHAAAA8JywenCSpIiICEVERGS6LCoqyux5QkJCzhcEAAAAAH/zTM+qBwAAAABPAsEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALCE4AAAAAYAHBCQAAAAAsIDgBAAAAgAUEJwAAAACwgOAEAAAAABYQnAAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQAAAIAFBCcAAAAAsIDgBAAAAAAWEJwAAAAAwAKCEwAAAABYQHACAAAAAAsITgAAAABgAcEJAAAAACwgOAEAAACABQQnAAAAALCA4AQAAAAAFhCcAAAAAMACghMAAAAAWEBwAgAAAAALnorgNH36dPn5+cnBwUEvvviidu7ced/+K1asUJkyZeTg4KCgoCCtX7/+CVUKAAAA4Hlk9eC0bNky9e3bV8OHD9fevXtVvnx5hYSE6MKFC5n2//nnn9WuXTu98cYb2rdvn1q2bKmWLVvq0KFDT7hyAAAAAM8LqwenTz75RD169FDXrl0VEBCgWbNmKU+ePJo/f36m/T/99FOFhoaqf//+Klu2rD766CNVrFhR06ZNe8KVAwAAAHhe5LLmzlNTU7Vnzx4NGjTI1GZjY6MGDRpox44dma6zY8cO9e3b16wtJCREq1evzrR/SkqKUlJSTM+vXbsmSbp+/fpjVp990lP+snYJmbpuMFq7hKxl8+uXdjMtW7eXnZLTnt7asvP36GbqjWzbVnZLuX3b2iVk6Wn6twzPn6f180t6fj7D+Px6NHx+Wd/T8vl1rw6j0fK/GVYNTpcuXVJaWpo8PT3N2j09PXX06NFM10lKSsq0f1JSUqb9x44dqxEjRmRo9/X1fcSqnx9u1i7gfj5+qqvLVlWtXcD9uD0/r8PTaug3vAZAZp7q34zn5DOMzy/cz9P2+fXnn3/KzcL7wqrB6UkYNGiQ2QhVenq6Ll++rPz588tgMFixMgDPm+vXr8vX11enT5+Wq6urtcsBAOCB/Vs/w4xGo/7880/5+PhY7GvV4FSgQAHZ2trq/PnzZu3nz5+Xl5dXput4eXk9VH97e3vZ29ubtbm7uz960QDwmFxdXf9VHzoAgOfHv/EzzNJI0z1WnRzCzs5OlSpV0pYtW0xt6enp2rJli6pXr57pOtWrVzfrL0mbNm3Ksj8AAAAAPC6rX6rXt29fde7cWZUrV1bVqlU1efJk3bhxQ127dpUkderUSYUKFdLYsWMlSe+++65q166tiRMnqmnTplq6dKl2796tzz77zJqHAQAAAOBfzOrBqW3btrp48aI+/PBDJSUlKTg4WBs2bDBNAJGYmCgbm/8bGHvppZe0ZMkSDR06VIMHD5a/v79Wr16tF154wVqHAAAPxN7eXsOHD89w+TAAAE87PsMkg/FB5t4DAAAAgOeY1b8AFwAAAACedgQnAAAAALCA4AQAAAAAFhCcAMCK/Pz8NHnyZGuXAQBAjoiKipLBYNDVq1etXcpjIzgBQCa6dOkig8FgeuTPn1+hoaE6cOBAtu5n165devPNN7N1mwAASNKOHTtka2urpk2bmrVHRkYqODg4Q3+DwaDVq1c/meKeQQQnAMhCaGiozp07p3PnzmnLli3KlSuXmjVrlq378PDwUJ48ebJ1mwAASNK8efP0zjvvaPv27Tp79qy1y3nmEZwAIAv29vby8vKSl5eXgoODNXDgQJ0+fVoXL16UJJ0+fVphYWFyd3dXvnz51KJFCyUkJJjW79Kli1q2bKkJEybI29tb+fPnV3h4uG7fvm3q889L9Y4ePaqXX35ZDg4OCggI0ObNm83+BzAhIUEGg0GrVq1S3bp1lSdPHpUvX147dux4EqcEAPCMSE5O1rJly9SzZ081bdpUCxculCQtXLhQI0aM0P79+01XVSxcuFB+fn6SpFatWslgMJiex8XFqUWLFvL09JSzs7OqVKmizZs3m+0rJSVFAwYMkK+vr+zt7VWyZEnNmzcv07r++usvNW7cWDVq1HjmLt8jOAHAA0hOTtbixYtVsmRJ5c+fX7dv31ZISIhcXFz0448/Kjo6Ws7OzgoNDVVqaqppva1btyouLk5bt27VokWLtHDhQtOH1z+lpaWpZcuWypMnj3799Vd99tlnGjJkSKZ9hwwZovfff18xMTEqVaqU2rVrpzt37uTEoQMAnkHLly9XmTJlVLp0af3nP//R/PnzZTQa1bZtW/Xr10+BgYGmqyratm2rXbt2SZIWLFigc+fOmZ4nJyerSZMm2rJli/bt26fQ0FA1b95ciYmJpn116tRJX331laZMmaLY2FjNnj1bzs7OGWq6evWqGjZsqPT0dG3atEnu7u5P5Fxkl1zWLgAAnlZr1641/cN/48YNeXt7a+3atbKxsdGSJUuUnp6uuXPnymAwSLr7YePu7q6oqCg1atRIkpQ3b15NmzZNtra2KlOmjJo2baotW7aoR48eGfa3adMmxcXFKSoqSl5eXpKk0aNHq2HDhhn6vv/++6Zr1keMGKHAwECdPHlSZcqUyZFzAQB4tsybN0//+c9/JN299PzatWvatm2b6tSpI2dnZ+XKlcv0WSNJjo6OkiR3d3ez9vLly6t8+fKm5x999JG++eYbrVmzRhERETp+/LiWL1+uTZs2qUGDBpKk4sWLZ6gnKSlJbdu2lb+/v5YsWSI7O7scOe6cxIgTAGShbt26iomJUUxMjHbu3KmQkBA1btxYp06d0v79+3Xy5Em5uLjI2dlZzs7Oypcvn27duqW4uDjTNgIDA2Vra2t67u3trQsXLmS6v2PHjsnX19fsA6tq1aqZ9i1XrpzZNiVluV0AwPPl2LFj2rlzp9q1aydJypUrl9q2bZvl5XP3k5ycrPfff19ly5aVu7u7nJ2dFRsbaxpxiomJka2trWrXrn3f7TRs2FAlS5bUsmXLnsnQJDHiBABZcnJyUsmSJU3P586dKzc3N82ZM0fJycmqVKmSvvzyywzreXh4mH7OnTu32TKDwaD09PTHru3v27034pUd2wUAPPvmzZunO3fuyMfHx9RmNBplb2+vadOmPdS23n//fW3atEkTJkxQyZIl5ejoqFdffdV0Wfq9kSpLmjZtqq+//lpHjhxRUFDQQ9XwtCA4AcADMhgMsrGx0c2bN1WxYkUtW7ZMBQsWlKura7Zsv3Tp0jp9+rTOnz8vT09PSTJdYw4AwIO4c+eOPv/8c02cONF02fg9LVu21FdffSU7OzulpaVlWDd37twZ2qOjo9WlSxe1atVK0t0RqL9PhBQUFKT09HRt27bNdKleZj7++GM5Ozurfv36ioqKUkBAwGMcpXVwqR4AZCElJUVJSUlKSkpSbGys3nnnHSUnJ6t58+bq0KGDChQooBYtWujHH39UfHy8oqKi1Lt3b505c+aR9tewYUOVKFFCnTt31oEDBxQdHa2hQ4dK+r9RJQAA7mft2rW6cuWK3njjDb3wwgtmjzZt2mjevHny8/NTfHy8YmJidOnSJaWkpEi6O9Prli1blJSUpCtXrkiS/P39tWrVKsXExGj//v1q37692RUOfn5+6ty5s7p166bVq1ebPg+XL1+eobYJEyaoQ4cOqlevno4ePfpkTkg2IjgBQBY2bNggb29veXt768UXX9SuXbu0YsUK1alTR3ny5NH27dtVpEgRtW7dWmXLltUbb7yhW7duPfIIlK2trVavXq3k5GRVqVJF3bt3N82q5+DgkJ2HBgD4l5o3b54aNGggNze3DMvatGmj3bt3KzAwUKGhoapbt648PDz01VdfSZImTpyoTZs2ydfXVxUqVJAkffLJJ8qbN69eeuklNW/eXCEhIapYsaLZdmfOnKlXX31VvXr1UpkyZdSjRw/duHEj0/omTZqksLAw1atXT8ePH8/mo89ZBqPRaLR2EQCAzEVHR+vll1/WyZMnVaJECWuXAwDAc4vgBABPkW+++UbOzs7y9/fXyZMn9e677ypv3rz66aefrF0aAADPNSaHAICnyJ9//qkBAwYoMTFRBQoUUIMGDTRx4kRrlwUAwHOPEScAAAAAsIDJIQAAAADAAoITAAAAAFhAcAIAAAAACwhOAAAAAGABwQkAAAAALCA4AQD+tQwGg1avXm3tMgAA/wIEJwDAMyspKUnvvPOOihcvLnt7e/n6+qp58+basmWLtUsDAPzL8AW4AIBnUkJCgmrUqCF3d3f997//VVBQkG7fvq2NGzcqPDxcR48etXaJAIB/EUacAADPpF69eslgMGjnzp1q06aNSpUqpcDAQPXt21e//PJLpusMGDBApUqVUp48eVS8eHENGzZMt2/fNi3fv3+/6tatKxcXF7m6uqpSpUravXu3JOnUqVNq3ry58ubNKycnJwUGBmr9+vVP5FgBANbHiBMA4Jlz+fJlbdiwQaNHj5aTk1OG5e7u7pmu5+LiooULF8rHx0cHDx5Ujx495OLiog8++ECS1KFDB1WoUEEzZ86Ura2tYmJilDt3bklSeHi4UlNTtX37djk5OenIkSNydnbOsWMEADxdCE4AgGfOyZMnZTQaVaZMmYdab+jQoaaf/fz89P7772vp0qWm4JSYmKj+/fubtuvv72/qn5iYqDZt2igoKEiSVLx48cc9DADAM4RL9QAAzxyj0fhI6y1btkw1atSQl5eXnJ2dNXToUCUmJpqW9+3bV927d1eDBg308ccfKy4uzrSsd+/eGjVqlGrUqKHhw4frwIEDj30cAIBnB8EJAPDM8ff3l8FgeKgJIHbs2KEOHTqoSZMmWrt2rfbt26chQ4YoNTXV1CcyMlKHDx9W06ZN9cMPPyggIEDffPONJKl79+767bff1LFjRx08eFCVK1fW1KlTs/3YAABPJ4PxUf/bDgAAK2rcuLEOHjyoY8eOZbjP6erVq3J3d5fBYNA333yjli1bauLEiZoxY4bZKFL37t21cuVKXb16NdN9tGvXTjdu3NCaNWsyLBs0aJDWrVvHyBMAPCcYcQIAPJOmT5+utLQ0Va1aVV9//bVOnDih2NhYTZkyRdWrV8/Q39/fX4mJiVq6dKni4uI0ZcoU02iSJN28eVMRERGKiorSqVOnFB0drV27dqls2bKSpD59+mjjxo2Kj4/X3r17tXXrVtMyAMC/H5NDAACeScWLF9fevXs1evRo9evXT+fOnZOHh4cq/b927dDGQiiKouhJ8Cg6+U2QkCAogAbA/AJIoAIkDWIQFIAgmQJGPDdj1tLXXLmT8/nkOI5f933f5/v9Zp7nPM+TruuyLEvWdU2SVFWV+74zjmOu60rTNBmGIdu2JUne9800TTnPM3Vdp23b7Pv+ly8D8I9M9QAAAApM9QAAAAqEEwAAQIFwAgAAKBBOAAAABcIJAACgQDgBAAAUCCcAAIAC4QQAAFAgnAAAAAqEEwAAQIFwAgAAKPgBh4QMjOgPz3QAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from sklearn.metrics import classification_report, confusion_matrix\n",
    "\n",
    "max_rtids_path = \"pretrained/max_RTIDS_pretrained.pt\"\n",
    "max_encon_path = \"pretrained/max_pretrained_enc.pt\"\n",
    "batch_size = 128\n",
    "dropout_rate = 0.5\n",
    "d_model = 32\n",
    "heads = 8\n",
    "N = 6\n",
    "trg_vocab = 2\n",
    "\n",
    "def evaluate_binary_classification(model, loader):\n",
    "    model.eval()\n",
    "    model.cuda()\n",
    "    true_labels = []\n",
    "    predicted_labels = []\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for src, trg, at_class in loader:\n",
    "            src, trg = src.to(\"cuda\"), trg.to(\"cuda\")\n",
    "            out = model(src)\n",
    "            predicted_labels.extend(torch.argmax(out, dim=1).cpu().numpy())\n",
    "            true_labels.extend(torch.argmax(trg, dim=1).cpu().numpy())\n",
    "\n",
    "    return true_labels, predicted_labels\n",
    "\n",
    "_, val_data = load_data()\n",
    "val_loader = get_data_loader(val_data, 128)\n",
    "\n",
    "if os.path.exists(max_rtids_path):\n",
    "    rtids_model = RTIDS_Transformer(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "    state = torch.load(max_rtids_path)\n",
    "    rtids_model.load_state_dict(state[\"model_state_dict\"])\n",
    "    \n",
    "if os.path.exists(max_encon_path):\n",
    "    encon_model = IDS_Encoder_Only(trg_vocab, d_model, N, heads, dropout_rate)\n",
    "    state = torch.load(max_encon_path)\n",
    "    encon_model.load_state_dict(state[\"model_state_dict\"])\n",
    "\n",
    "true_labels_rtids, predicted_labels_rtids = evaluate_binary_classification(rtids_model, val_loader)\n",
    "classification_rep_rtids = classification_report(true_labels_rtids, predicted_labels_rtids, target_names=[\"Benign\", \"Attack\"], output_dict=True)\n",
    "\n",
    "true_labels_encon, predicted_labels_encon = evaluate_binary_classification(encon_model, val_loader)\n",
    "classification_rep_encon = classification_report(true_labels_encon, predicted_labels_encon, target_names=[\"Benign\", \"Attack\"], output_dict=True)\n",
    "\n",
    "class_names = [\"Benign\", \"Attack\"]\n",
    "metrics = [\"precision\", \"recall\", \"f1-score\"]\n",
    "rtids_metrics = {metric: [classification_rep_rtids[class_name][metric] for class_name in class_names] for metric in metrics}\n",
    "encon_metrics = {metric: [classification_rep_encon[class_name][metric] for class_name in class_names] for metric in metrics}\n",
    "\n",
    "bar_width = 0.09\n",
    "index = np.arange(len(class_names), dtype=float)\n",
    "fig, ax = plt.subplots(figsize=(10, 6))\n",
    "\n",
    "for i, metric in enumerate(metrics):\n",
    "    rtids_bars = ax.bar(index - bar_width/2, rtids_metrics[metric], bar_width, label=f\"RTIDS {metric}\")\n",
    "    encon_bars = ax.bar(index + bar_width/2, encon_metrics[metric], bar_width, label=f\"Encoder Only {metric}\")\n",
    "    \n",
    "    index += bar_width*2.5\n",
    "\n",
    "ax.set_xlabel(\"Class\")\n",
    "ax.set_ylabel(\"Scores\")\n",
    "ax.set_title(\"Classification Metrics Comparison per Class\")\n",
    "ax.set_xticks(index - bar_width/2 - (bar_width/2 * len(metrics)))\n",
    "ax.set_xticklabels(class_names)\n",
    "ax.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a67bb74",
   "metadata": {},
   "source": [
    "## Discussion\n",
    "In comparison to the original RTIDS paper, which calimed to have achieved an accuracy of 99.35% my attempt did not perform as well. This might have several reasons:\n",
    "* The original RTIDS Model has been trained on a larger Dataset. Meanwhile I had to undersample the data to enable my PC to process them, leaving me with potentially way less samples than the original workgroup.\n",
    "* The Exact SMOTE Approach was not explained, so I might have used a different approach\n",
    "* Some implementation details were not given in the original Paper (such as the model dimension and the Embedding Technique) and had to be estimated.\n",
    "* Some Formulas in the original Paper seemed wrong or misleading, such as the double inclusion of the ReLU Function in the Feed Forward Network Calculation\n",
    "* The Architecture Figure in the original Paper was either wrong or misleading, I opted to implement the transformer the usual transformer way (inputting the Encoder Output into the Decoder Multi Head Attention Layer instead of the Sequence input)\n",
    "\n",
    "Another quite significant difference to the original Paper can be found in regards to training time. Training the model locally on my machine took roughly 33 Hours to complete the training (~110 minutes per Epoch) and roughly 10 minutes to evaluate the model. However the original paper claims to only have taken 195.6 seconds which seems definitely impossible. I can only assume that this is the time taken for evaluating the model on a better GPU than i have available, but I cannot say this with any certainty.\n",
    "\n",
    "\n",
    "### Comparison to Encoder Only Architecture\n",
    "\n",
    "As stated above, usually for Classification-Problems, an Encoder-Only Transformer Architecture is used. As evident in the Analysis above, in this case the Encoder-Only Architecture performed only slightly worse, achieving a maximum accuracy of merely 85% while my RTIDS implementation achieves 86% Accuracy. A reason for this might be the overall fewer trainable Parameters for such a complex Problem, especially the abscence of masking and multiple Attention Layers might be a factor in the reduced performance.\n",
    "\n",
    "Overall the models perform very similarly, especially in regards to the Performance scores on \"Attack\"/\"Benign\" Classification. Both models share an extremely similar behaviour in Precision, Recall and F1-Score.\n",
    "\n",
    "However besides the performance difference, there is also some other differences between the models. The Encoder Only Architecture trains in roughly a third of the time it takes for the RTIDS Model to train, obviously because of the fewer Parameters. At the same time, the early epochs (especially the first one) seem to train faster, achieving almost 84% Accuracy after just two Epochs. \n",
    "\n",
    "Especially considering the largely reduced training and evaluation time, the more stable training and the almost even performance, the Encoder-Only Architecture proves to be a viable alternative to the proposed RTIDS Architecture."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a97fac04",
   "metadata": {},
   "source": [
    "## Resources\n",
    "- Z. Wu et al.: RTIDS: A Robust Transformer-Based Approach for Intrusion Detection System, Jun. 2022\n",
    "  Link: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9794665\n",
    "- Vaswani et al.: Attention is All you Need, 2017\n",
    "  Link: https://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf\n",
    "- Gorishniy et al.: Revisiting Deep Learning Models for Tabular Data, Nov 2021\n",
    "  Link: https://arxiv.org/pdf/2106.11959v2.pdf\n",
    "- (Mis)use of the CICIDS 2017 Dataset in Information Security Research, Nov. 2022\n",
    "  Link: https://www.researchgate.net/publication/365062293_Misuse_of_the_CICIDS_2017_Dataset_in_Information_Security_Research\n",
    "- G. Giacaglia: How Transformers Work, Mar 2019\n",
    "  Link: https://towardsdatascience.com/transformers-141e32e69591"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
